From 8cb34fb7e7d512dc146c3a49579bcaf37f86f092 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 12 Jul 2022 16:36:12 +0800 Subject: [PATCH 001/338] Add unit test --- .../acl/plain/PlainPermissionManagerTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainPermissionManagerTest.java b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainPermissionManagerTest.java index 0706b850c5..eafc623454 100644 --- a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainPermissionManagerTest.java +++ b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainPermissionManagerTest.java @@ -29,6 +29,7 @@ import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.AclUtils; import org.apache.rocketmq.acl.common.Permission; import org.apache.rocketmq.common.PlainAccessConfig; +import org.assertj.core.util.Lists; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -300,4 +301,28 @@ public class PlainPermissionManagerTest { transport.delete(); System.setProperty("rocketmq.home.dir", "src/test/resources"); } + + @Test + public void updateAccessConfigTest() { + Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(null)); + + plainAccessConfig.setAccessKey("admin_test"); + // Invalid parameter + plainAccessConfig.setSecretKey("123456"); + plainAccessConfig.setAdmin(true); + Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(plainAccessConfig)); + + plainAccessConfig.setSecretKey("12345678"); + // Invalid parameter + plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA!SUB")); + Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(plainAccessConfig)); + + // first update + plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA=SUB")); + plainPermissionManager.updateAccessConfig(plainAccessConfig); + + // second update + plainAccessConfig.setTopicPerms(Lists.newArrayList("topicA=SUB")); + plainPermissionManager.updateAccessConfig(plainAccessConfig); + } } From 8d203e84725503a964f33cb28aa431675916e0df Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 9 Mar 2022 15:36:19 +0800 Subject: [PATCH 002/338] [ISSUE #3949] Add rocketmq-proto dependency. First commit of gRPC. Add rocketmq-proto dependency and related pom.xml. --- grpc/pom.xml | 39 +++++++++++++++++++++++++++++++++++++++ pom.xml | 1 + 2 files changed, 40 insertions(+) create mode 100644 grpc/pom.xml diff --git a/grpc/pom.xml b/grpc/pom.xml new file mode 100644 index 0000000000..6c57876205 --- /dev/null +++ b/grpc/pom.xml @@ -0,0 +1,39 @@ + + + + + org.apache.rocketmq + rocketmq-all + 5.0.0-BETA-SNAPSHOT + + + 4.0.0 + jar + rocketmq-grpc + rocketmq-grpc ${project.version} + + + + org.apache.rocketmq + rocketmq-proto + 5.0.0-SNAPSHOT + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5f6c4ed703..ee06104229 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,7 @@ acl example container + grpc From 3134916c538ab7d830fd42cb3735c36f10eb5e5d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 10 Mar 2022 14:39:12 +0800 Subject: [PATCH 003/338] [ISSUE #3949] Initialize basic structure --- common/pom.xml | 5 + .../rocketmq/common/constant/LoggerName.java | 1 + .../rocketmq/common/logger/ProxyLogger.java | 26 ++++ .../common/logger/WatermarkLogger.java | 28 ++++ .../common/thread/ThreadPoolMonitor.java | 122 +++++++++++++++++ .../thread/ThreadPoolQueueSizeMonitor.java | 44 +++++++ .../thread/ThreadPoolStatusMonitor.java | 29 ++++ .../common/thread/ThreadPoolWrapper.java | 124 ++++++++++++++++++ grpc/pom.xml | 39 ------ pom.xml | 40 +++++- proxy/pom.xml | 86 ++++++++++++ .../proxy/configuration/Configuration.java | 61 +++++++++ .../configuration/ConfigurationManager.java | 48 +++++++ .../proxy/configuration/ProxyConfig.java | 122 +++++++++++++++++ .../proxy/grpc/GrpcMessagingProcessor.java | 29 ++++ .../rocketmq/proxy/grpc/GrpcServer.java | 116 ++++++++++++++++ .../rocketmq/proxy/grpc/common/Converter.java | 21 +++ .../rocketmq/proxy/grpc/common/ProxyMode.java | 43 ++++++ .../proxy/grpc/common/ResponseBuilder.java | 35 +++++ .../grpc/service/ClusterGrpcService.java | 35 +++++ .../proxy/grpc/service/GrpcService.java | 25 ++++ .../proxy/grpc/service/LocalGrpcService.java | 37 ++++++ 22 files changed, 1076 insertions(+), 40 deletions(-) create mode 100644 common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolQueueSizeMonitor.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolStatusMonitor.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java delete mode 100644 grpc/pom.xml create mode 100644 proxy/pom.xml create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/configuration/Configuration.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java diff --git a/common/pom.xml b/common/pom.xml index cea58306ae..ad2046a28f 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -44,5 +44,10 @@ com.google.guava guava + + org.slf4j + slf4j-api + 1.7.7 + 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 a77d5c2d21..151cbf460c 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 @@ -44,4 +44,5 @@ public class LoggerName { public static final String ROCKETMQ_POP_LOGGER_NAME = "RocketmqPop"; public static final String FAILOVER_LOGGER_NAME = "RocketmqFailover"; public static final String STDOUT_LOGGER_NAME = "STDOUT"; + public static final String GRPC_LOGGER_NAME = "RocketmqGrpc"; } diff --git a/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java b/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java new file mode 100644 index 0000000000..1e51ed9d8d --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.common.logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyLogger { + public static final Logger LOG_WATER_MARK = LoggerFactory.getLogger("Watermark"); + public static final Logger LOG_JSTACK = LoggerFactory.getLogger("Jstack"); +} diff --git a/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java b/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java new file mode 100644 index 0000000000..9e57d02c8f --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java @@ -0,0 +1,28 @@ +/* + * 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.common.logger; + +import org.slf4j.Logger; + +public class WatermarkLogger { + private static final Logger LOG_MSG_TRACE = ProxyLogger.LOG_WATER_MARK; + + public static void info(String name, String k, double v) { + LOG_MSG_TRACE.info("\t{}\t{}\t{}", name, k, v); + } +} 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 new file mode 100644 index 0000000000..6db0b2f15a --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolMonitor.java @@ -0,0 +1,122 @@ +/* + * 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.common.thread; + +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +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.logger.ProxyLogger; +import org.apache.rocketmq.common.logger.WatermarkLogger; + +public class ThreadPoolMonitor { + private static final List MONITOR_EXECUTOR = new CopyOnWriteArrayList<>(); + private static final ScheduledExecutorService MONITOR_SCHEDULED = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder().setNameFormat("ThreadPoolMonitor-%d").build() + ); + + private static volatile boolean enablePrintJstack = true; + private static volatile long jstackPeriodTIme = 60000; + private static volatile long jstackTime = System.currentTimeMillis(); + + public static void config(boolean enablePrintJstack, long jstackPeriodTime) { + ThreadPoolMonitor.enablePrintJstack = enablePrintJstack; + jstackPeriodTIme = jstackPeriodTime; + } + + public static ThreadPoolExecutor createAndMonitor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + String name, + int queueCapacity) { + return createAndMonitor(corePoolSize, maximumPoolSize, keepAliveTime, unit, name, queueCapacity, Collections.emptyList()); + } + + public static ThreadPoolExecutor createAndMonitor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + String name, + int queueCapacity, + ThreadPoolStatusMonitor... threadPoolStatusMonitors) { + return createAndMonitor(corePoolSize, maximumPoolSize, keepAliveTime, unit, name, queueCapacity, + Lists.newArrayList(threadPoolStatusMonitors)); + } + + public static ThreadPoolExecutor createAndMonitor(int corePoolSize, + int maximumPoolSize, + long keepAliveTime, + TimeUnit unit, + String name, + int queueCapacity, + List threadPoolStatusMonitors) { + ThreadPoolExecutor executor = new ThreadPoolExecutor( + corePoolSize, + maximumPoolSize, + keepAliveTime, + unit, + new LinkedBlockingQueue<>(queueCapacity), + new ThreadFactoryBuilder().setNameFormat(name + "-%d").build(), + new ThreadPoolExecutor.DiscardOldestPolicy()); + List printers = Lists.newArrayList(new ThreadPoolQueueSizeMonitor(queueCapacity)); + printers.addAll(threadPoolStatusMonitors); + + MONITOR_EXECUTOR.add(ThreadPoolWrapper.builder() + .name(name) + .threadPoolExecutor(executor) + .statusPrinters(printers) + .build()); + return executor; + } + + public static void logThreadPoolStatus() { + for (ThreadPoolWrapper threadPoolWrapper : MONITOR_EXECUTOR) { + List monitors = threadPoolWrapper.getStatusPrinters(); + for (ThreadPoolStatusMonitor monitor : monitors) { + double value = monitor.value(threadPoolWrapper.getThreadPoolExecutor()); + WatermarkLogger.info(threadPoolWrapper.getName(), + monitor.describe(), + value); + + if (enablePrintJstack) { + if (monitor.needPrintJstack(threadPoolWrapper.getThreadPoolExecutor(), value) && + System.currentTimeMillis() - jstackTime > jstackPeriodTIme) { + jstackTime = System.currentTimeMillis(); + ProxyLogger.LOG_JSTACK.warn("jstack start \n " + UtilAll.jstack()); + } + } + } + } + } + + public static void init() { + MONITOR_SCHEDULED.scheduleAtFixedRate(ThreadPoolMonitor::logThreadPoolStatus, 20, 1, TimeUnit.SECONDS); + } + + public static void shutdown() { + MONITOR_SCHEDULED.shutdown(); + } +} \ No newline at end of file diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolQueueSizeMonitor.java b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolQueueSizeMonitor.java new file mode 100644 index 0000000000..9e2e2f675c --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolQueueSizeMonitor.java @@ -0,0 +1,44 @@ +/* + * 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.common.thread; + +import java.util.concurrent.ThreadPoolExecutor; + +public class ThreadPoolQueueSizeMonitor implements ThreadPoolStatusMonitor { + + private final int maxQueueCapacity; + + public ThreadPoolQueueSizeMonitor(int maxQueueCapacity) { + this.maxQueueCapacity = maxQueueCapacity; + } + + @Override + public String describe() { + return "queueSize"; + } + + @Override + public double value(ThreadPoolExecutor executor) { + return executor.getQueue().size(); + } + + @Override + public boolean needPrintJstack(ThreadPoolExecutor executor, double value) { + return value > maxQueueCapacity * 0.85; + } +} diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolStatusMonitor.java b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolStatusMonitor.java new file mode 100644 index 0000000000..548fec52ec --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolStatusMonitor.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.common.thread; + +import java.util.concurrent.ThreadPoolExecutor; + +public interface ThreadPoolStatusMonitor { + + String describe(); + + double value(ThreadPoolExecutor executor); + + boolean needPrintJstack(ThreadPoolExecutor executor, double value); +} \ No newline at end of file diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java new file mode 100644 index 0000000000..653fa1d833 --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java @@ -0,0 +1,124 @@ +/* + * 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.common.thread; + +import com.google.common.base.Objects; +import java.util.List; +import java.util.concurrent.ThreadPoolExecutor; + +public class ThreadPoolWrapper { + private String name; + private ThreadPoolExecutor threadPoolExecutor; + private List statusPrinters; + + ThreadPoolWrapper(final String name, final ThreadPoolExecutor threadPoolExecutor, + final List statusPrinters) { + this.name = name; + this.threadPoolExecutor = threadPoolExecutor; + this.statusPrinters = statusPrinters; + } + + public static class ThreadPoolWrapperBuilder { + private String name; + private ThreadPoolExecutor threadPoolExecutor; + private List statusPrinters; + + ThreadPoolWrapperBuilder() { + } + + public ThreadPoolWrapper.ThreadPoolWrapperBuilder name(final String name) { + this.name = name; + return this; + } + + public ThreadPoolWrapper.ThreadPoolWrapperBuilder threadPoolExecutor( + final ThreadPoolExecutor threadPoolExecutor) { + this.threadPoolExecutor = threadPoolExecutor; + return this; + } + + public ThreadPoolWrapper.ThreadPoolWrapperBuilder statusPrinters( + final List statusPrinters) { + this.statusPrinters = statusPrinters; + return this; + } + + public ThreadPoolWrapper build() { + return new ThreadPoolWrapper(this.name, this.threadPoolExecutor, this.statusPrinters); + } + + @java.lang.Override + public java.lang.String toString() { + return "ThreadPoolWrapper.ThreadPoolWrapperBuilder(name=" + this.name + ", threadPoolExecutor=" + this.threadPoolExecutor + ", statusPrinters=" + this.statusPrinters + ")"; + } + } + + public static ThreadPoolWrapper.ThreadPoolWrapperBuilder builder() { + return new ThreadPoolWrapper.ThreadPoolWrapperBuilder(); + } + + public String getName() { + return this.name; + } + + public ThreadPoolExecutor getThreadPoolExecutor() { + return this.threadPoolExecutor; + } + + public List getStatusPrinters() { + return this.statusPrinters; + } + + public void setName(final String name) { + this.name = name; + } + + public void setThreadPoolExecutor(final ThreadPoolExecutor threadPoolExecutor) { + this.threadPoolExecutor = threadPoolExecutor; + } + + public void setStatusPrinters(final List statusPrinters) { + this.statusPrinters = statusPrinters; + } + + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ThreadPoolWrapper wrapper = (ThreadPoolWrapper) o; + return Objects.equal(name, wrapper.name) && Objects.equal(threadPoolExecutor, wrapper.threadPoolExecutor) && Objects.equal(statusPrinters, wrapper.statusPrinters); + } + + @Override public int hashCode() { + return Objects.hashCode(name, threadPoolExecutor, statusPrinters); + } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder("ThreadPoolWrapper{"); + sb.append("name='") + .append(name) + .append('\''); + sb.append(", threadPoolExecutor=") + .append(threadPoolExecutor); + sb.append(", statusPrinters=") + .append(statusPrinters); + sb.append('}'); + return sb.toString(); + } +} diff --git a/grpc/pom.xml b/grpc/pom.xml deleted file mode 100644 index 6c57876205..0000000000 --- a/grpc/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - org.apache.rocketmq - rocketmq-all - 5.0.0-BETA-SNAPSHOT - - - 4.0.0 - jar - rocketmq-grpc - rocketmq-grpc ${project.version} - - - - org.apache.rocketmq - rocketmq-proto - 5.0.0-SNAPSHOT - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index ee06104229..09a1af5226 100644 --- a/pom.xml +++ b/pom.xml @@ -103,6 +103,7 @@ ${project.basedir}/../test/target/jacoco-it.exec file:**/generated-sources/**,**/test/** + 1.38.0 @@ -122,7 +123,7 @@ acl example container - grpc + proxy @@ -525,6 +526,11 @@ rocketmq-example ${project.version} + + ${project.groupId} + rocketmq-grpc + ${project.version} + org.slf4j slf4j-api @@ -627,6 +633,38 @@ logback-core 1.1.11 + + io.grpc + grpc-netty-shaded + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + + + io.grpc + grpc-services + ${grpc.version} + + + io.grpc + grpc-testing + ${grpc.version} + test + + + com.google.protobuf + protobuf-java-util + 3.17.2 + + diff --git a/proxy/pom.xml b/proxy/pom.xml new file mode 100644 index 0000000000..b2d0759faf --- /dev/null +++ b/proxy/pom.xml @@ -0,0 +1,86 @@ + + + + + + rocketmq-all + org.apache.rocketmq + 5.0.0-BETA-SNAPSHOT + + + 4.0.0 + jar + rocketmq-proxy + rocketmq-proxy ${project.version} + + + 8 + 8 + + + + + org.apache.rocketmq + rocketmq-proto + 5.0.0-SNAPSHOT + + + io.grpc + grpc-netty-shaded + + + io.grpc + grpc-protobuf + + + io.grpc + grpc-stub + + + io.grpc + grpc-services + + + com.google.protobuf + protobuf-java-util + + + org.apache.rocketmq + rocketmq-broker + + + org.apache.rocketmq + rocketmq-common + + + org.apache.commons + commons-lang3 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/Configuration.java new file mode 100644 index 0000000000..6ee3f3f40a --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/Configuration.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.configuration; + +import com.alibaba.fastjson.JSON; +import java.io.File; +import java.nio.file.Files; +import java.util.concurrent.atomic.AtomicReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Configuration { + private final static Logger log = LoggerFactory.getLogger(Configuration.class); + private final AtomicReference proxyConfigReference = new AtomicReference<>(); + + public void init() throws Exception { + String proxyConfigData = loadJsonConfig(ProxyConfig.CONFIG_FILE_NAME); + ProxyConfig proxyConfig = JSON.parseObject(proxyConfigData, ProxyConfig.class); + setProxyConfig(proxyConfig); + } + + public static String loadJsonConfig(String configFileName) throws Exception { + String filePath = new File(ConfigurationManager.getProxyHome() + File.separator + "conf", configFileName).toString(); + + File file = new File(filePath); + if (!file.exists()) { + log.warn("the config file {} not exist", filePath); + return null; + } + long fileLength = file.length(); + if (fileLength <= 0) { + log.warn("the config file {} length is zero", filePath); + return null; + } + + return new String(Files.readAllBytes(file.toPath())); + } + + public ProxyConfig getProxyConfig() { + return proxyConfigReference.get(); + } + + public void setProxyConfig(ProxyConfig proxyConfig) { + proxyConfigReference.set(proxyConfig); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java new file mode 100644 index 0000000000..2ee1a61f04 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java @@ -0,0 +1,48 @@ +/* + * 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.configuration; + +import java.io.File; +import org.apache.commons.lang3.StringUtils; + +public class ConfigurationManager { + private static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; + private static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; + private static String proxyHome; + private static Configuration configuration; + + public static void initEnv() { + proxyHome = System.getenv(RMQ_PROXY_HOME); + if (StringUtils.isEmpty(proxyHome)) { + proxyHome = System.getProperty(RMQ_PROXY_HOME, DEFAULT_RMQ_PROXY_HOME); + } + } + + public static void intConfig() throws Exception { + configuration = new Configuration(); + configuration.init(); + } + + public static String getProxyHome() { + return proxyHome; + } + + public static ProxyConfig getProxyConfig() { + return configuration.getProxyConfig(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java new file mode 100644 index 0000000000..c0aa518caa --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -0,0 +1,122 @@ +/* + * 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.configuration; + +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; + +public class ProxyConfig { + public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; + + /** + * gRPC + */ + private String proxyMode = ProxyMode.CLUSTER.name(); + private Boolean startGrpcServer = true; + private Integer grpcServerPort = 8081; + private String grpcTlsKeyPath = "/home/admin/rmq-gateway/conf/tls/gRPC.key.pem"; + private String grpcTlsCertPath = "/home/admin/rmq-gateway/conf/tls/gRPC.chain.cert.pem"; + private int grpcBossLoopNum = 1; + private int grpcWorkerLoopNum = Runtime.getRuntime().availableProcessors() * 2; + private int grpcThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2; + private int grpcThreadPoolQueueCapacity = 100000; + /** + * gRPC max message size + * 130M = 4M * 32 messages + 2M attributes + */ + private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; + + public String getProxyMode() { + return proxyMode; + } + + public void setProxyMode(String proxyMode) { + this.proxyMode = proxyMode; + } + + public Boolean getStartGrpcServer() { + return startGrpcServer; + } + + public void setStartGrpcServer(Boolean startGrpcServer) { + this.startGrpcServer = startGrpcServer; + } + + public Integer getGrpcServerPort() { + return grpcServerPort; + } + + public void setGrpcServerPort(Integer grpcServerPort) { + this.grpcServerPort = grpcServerPort; + } + + public String getGrpcTlsKeyPath() { + return grpcTlsKeyPath; + } + + public void setGrpcTlsKeyPath(String grpcTlsKeyPath) { + this.grpcTlsKeyPath = grpcTlsKeyPath; + } + + public String getGrpcTlsCertPath() { + return grpcTlsCertPath; + } + + public void setGrpcTlsCertPath(String grpcTlsCertPath) { + this.grpcTlsCertPath = grpcTlsCertPath; + } + + public int getGrpcBossLoopNum() { + return grpcBossLoopNum; + } + + public void setGrpcBossLoopNum(int grpcBossLoopNum) { + this.grpcBossLoopNum = grpcBossLoopNum; + } + + public int getGrpcWorkerLoopNum() { + return grpcWorkerLoopNum; + } + + public void setGrpcWorkerLoopNum(int grpcWorkerLoopNum) { + this.grpcWorkerLoopNum = grpcWorkerLoopNum; + } + + public int getGrpcThreadPoolNums() { + return grpcThreadPoolNums; + } + + public void setGrpcThreadPoolNums(int grpcThreadPoolNums) { + this.grpcThreadPoolNums = grpcThreadPoolNums; + } + + public int getGrpcThreadPoolQueueCapacity() { + return grpcThreadPoolQueueCapacity; + } + + public void setGrpcThreadPoolQueueCapacity(int grpcThreadPoolQueueCapacity) { + this.grpcThreadPoolQueueCapacity = grpcThreadPoolQueueCapacity; + } + + public int getGrpcMaxInboundMessageSize() { + return grpcMaxInboundMessageSize; + } + + public void setGrpcMaxInboundMessageSize(int grpcMaxInboundMessageSize) { + this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java new file mode 100644 index 0000000000..297a32f29c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc; + +import apache.rocketmq.v1.MessagingServiceGrpc; +import org.apache.rocketmq.proxy.grpc.service.GrpcService; + +public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { + private final GrpcService grpcService; + + public GrpcMessagingProcessor(GrpcService grpcService) { + this.grpcService = grpcService; + } +} 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 new file mode 100644 index 0000000000..a0aa501def --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServer.java @@ -0,0 +1,116 @@ +/* + * 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.grpc; + +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup; +import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; +import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.service.GrpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GrpcServer { + + private static final Logger log = LoggerFactory.getLogger(GrpcServer.class); + + private final io.grpc.Server server; + + private final ThreadPoolExecutor executor; + + public GrpcServer(GrpcService grpcService) { + int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); + NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(port); + + // add tls files + String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); + String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); + try { + InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); + InputStream serverCertificateStream = new FileInputStream(tlsCertPath); + + SslContext sslContext = GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .clientAuth(ClientAuth.NONE) + .build(); + serverBuilder.sslContext(sslContext); + } catch (IOException e) { + log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); + throw new RuntimeException("grpc tls set failed: " + e.getMessage()); + } + + // create executor + int threadPoolNums = ConfigurationManager.getProxyConfig().getGrpcThreadPoolNums(); + int threadPoolQueueCapacity = ConfigurationManager.getProxyConfig().getGrpcThreadPoolQueueCapacity(); + this.executor = ThreadPoolMonitor.createAndMonitor( + threadPoolNums, + threadPoolNums, + 1, TimeUnit.MINUTES, + "GrpcRequestExecutorThread", + threadPoolQueueCapacity + ); + + GrpcMessagingProcessor messagingProcessor = new GrpcMessagingProcessor(grpcService); + + // build server + int bossLoopNum = ConfigurationManager.getProxyConfig().getGrpcBossLoopNum(); + int workerLoopNum = ConfigurationManager.getProxyConfig().getGrpcWorkerLoopNum(); + int maxInboundMessageSize = ConfigurationManager.getProxyConfig().getGrpcMaxInboundMessageSize(); + + this.server = serverBuilder + .maxInboundMessageSize(maxInboundMessageSize) + .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) + .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) + .channelType(NioServerSocketChannel.class) + .addService(messagingProcessor) + .executor(this.executor) + .build(); + + log.info( + "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", + port, tlsKeyPath, tlsCertPath, threadPoolNums, threadPoolQueueCapacity, + bossLoopNum, workerLoopNum, maxInboundMessageSize); + } + + public void start() throws Exception { + this.server.start(); + log.info("grpc server has started"); + } + + public void shutdown() { + try { + this.server.shutdown().awaitTermination(30, TimeUnit.SECONDS); + this.executor.shutdown(); + + log.info("grpc server has stopped"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java new file mode 100644 index 0000000000..bb1737353f --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -0,0 +1,21 @@ +/* + * 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.grpc.common; + +public class Converter { +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java new file mode 100644 index 0000000000..acf8ea32c6 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java @@ -0,0 +1,43 @@ +/* + * 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.grpc.common; + +public enum ProxyMode { + LOCAL("LOCAL"), + CLUSTER("CLUSTER"); + + private final String mode; + + ProxyMode(String mode) { + this.mode = mode; + } + + public static boolean isClusterMode(String mode) { + if (mode == null) { + return false; + } + return CLUSTER.mode.equals(mode.toUpperCase()); + } + + public static boolean isLocalMode(String mode) { + if (mode == null) { + return false; + } + return LOCAL.mode.equals(mode.toUpperCase()); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java new file mode 100644 index 0000000000..7265295efc --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.common; + +import apache.rocketmq.v1.ResponseCommon; +import com.google.rpc.Code; +import com.google.rpc.Status; + +public class ResponseBuilder { + public static ResponseCommon buildCommon(Code code, String message) { + Status status = Status.newBuilder() + .setCode(code.getNumber()) + .setMessage(message) + .build(); + + return ResponseCommon.newBuilder() + .setStatus(status) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java new file mode 100644 index 0000000000..aac84bec8f --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.service; + +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HealthCheckResponse; +import com.google.rpc.Code; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterGrpcService implements GrpcService { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + public ClusterGrpcService() { + + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java new file mode 100644 index 0000000000..fbe0136dd5 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.service; + +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HealthCheckResponse; +import java.util.concurrent.CompletableFuture; + +public interface GrpcService { +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java new file mode 100644 index 0000000000..55f746e494 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.service; + +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HealthCheckResponse; +import com.google.rpc.Code; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LocalGrpcService implements GrpcService { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final BrokerController brokerController; + + public LocalGrpcService(BrokerController brokerController) { + this.brokerController = brokerController; + } +} From 57a549a95840b1bf7a621450b1cb705da7f71f50 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 10 Mar 2022 19:24:44 +0800 Subject: [PATCH 004/338] [ISSUE #3949] Add interface for GrpcService --- .../grpc/service/ClusterGrpcService.java | 112 +++++++++++++++++- .../proxy/grpc/service/GrpcService.java | 73 +++++++++++- .../proxy/grpc/service/LocalGrpcService.java | 112 +++++++++++++++++- 3 files changed, 290 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index aac84bec8f..a49a2ecb6a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -17,12 +17,43 @@ package org.apache.rocketmq.proxy.grpc.service; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.HealthCheckRequest; import apache.rocketmq.v1.HealthCheckResponse; -import com.google.rpc.Code; -import java.util.concurrent.CompletableFuture; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; +import apache.rocketmq.v1.ReportThreadStackTraceRequest; +import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.grpc.Context; +import io.netty.util.concurrent.CompleteFuture; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,4 +63,79 @@ public class ClusterGrpcService implements GrpcService { public ClusterGrpcService() { } + + @Override public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { + return null; + } + + @Override public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { + return null; + } + + @Override public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { + return null; + } + + @Override public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + return null; + } + + @Override + public CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + return null; + } + + @Override public CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + return null; + } + + @Override public CompleteFuture ackMessage(Context ctx, AckMessageRequest request) { + return null; + } + + @Override public CompleteFuture nackMessage(Context ctx, NackMessageRequest request) { + return null; + } + + @Override + public CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + return null; + } + + @Override public CompleteFuture endTransaction(Context ctx, EndTransactionRequest request) { + return null; + } + + @Override public CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request) { + return null; + } + + @Override public CompleteFuture pullMessage(Context ctx, PullMessageRequest request) { + return null; + } + + @Override public CompleteFuture pollCommand(Context ctx, PollCommandRequest request) { + return null; + } + + @Override public CompleteFuture reportThreadStackTrace(Context ctx, + ReportThreadStackTraceRequest request) { + return null; + } + + @Override public CompleteFuture reportMessageConsumptionResult(Context ctx, + ReportMessageConsumptionResultRequest request) { + return null; + } + + @Override public CompleteFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request) { + return null; + } + + @Override public CompleteFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + return null; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java index fbe0136dd5..9666eeddba 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java @@ -17,9 +17,80 @@ package org.apache.rocketmq.proxy.grpc.service; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.HealthCheckRequest; import apache.rocketmq.v1.HealthCheckResponse; -import java.util.concurrent.CompletableFuture; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; +import apache.rocketmq.v1.ReportThreadStackTraceRequest; +import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.grpc.Context; +import io.netty.util.concurrent.CompleteFuture; public interface GrpcService { + CompleteFuture queryRoute(Context ctx, QueryRouteRequest request); + + CompleteFuture heartbeat(Context ctx, HeartbeatRequest request); + + CompleteFuture healthCheck(Context ctx, HealthCheckRequest request); + + CompleteFuture sendMessage(Context ctx, SendMessageRequest request); + + CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request); + + CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request); + + CompleteFuture ackMessage(Context ctx, AckMessageRequest request); + + CompleteFuture nackMessage(Context ctx, NackMessageRequest request); + + CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request); + + CompleteFuture endTransaction(Context ctx, EndTransactionRequest request); + + CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request); + + CompleteFuture pullMessage(Context ctx, PullMessageRequest request); + + CompleteFuture pollCommand(Context ctx, PollCommandRequest request); + + CompleteFuture reportThreadStackTrace(Context ctx, + ReportThreadStackTraceRequest request); + + CompleteFuture reportMessageConsumptionResult(Context ctx, + ReportMessageConsumptionResultRequest request); + + CompleteFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request); + + CompleteFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 55f746e494..348d94d6f8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -17,13 +17,44 @@ package org.apache.rocketmq.proxy.grpc.service; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.HealthCheckRequest; import apache.rocketmq.v1.HealthCheckResponse; -import com.google.rpc.Code; -import java.util.concurrent.CompletableFuture; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; +import apache.rocketmq.v1.ReportThreadStackTraceRequest; +import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.grpc.Context; +import io.netty.util.concurrent.CompleteFuture; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,4 +65,79 @@ public class LocalGrpcService implements GrpcService { public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; } + + @Override public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { + return null; + } + + @Override public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { + return null; + } + + @Override public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { + return null; + } + + @Override public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + return null; + } + + @Override + public CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + return null; + } + + @Override public CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + return null; + } + + @Override public CompleteFuture ackMessage(Context ctx, AckMessageRequest request) { + return null; + } + + @Override public CompleteFuture nackMessage(Context ctx, NackMessageRequest request) { + return null; + } + + @Override + public CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + return null; + } + + @Override public CompleteFuture endTransaction(Context ctx, EndTransactionRequest request) { + return null; + } + + @Override public CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request) { + return null; + } + + @Override public CompleteFuture pullMessage(Context ctx, PullMessageRequest request) { + return null; + } + + @Override public CompleteFuture pollCommand(Context ctx, PollCommandRequest request) { + return null; + } + + @Override public CompleteFuture reportThreadStackTrace(Context ctx, + ReportThreadStackTraceRequest request) { + return null; + } + + @Override public CompleteFuture reportMessageConsumptionResult(Context ctx, + ReportMessageConsumptionResultRequest request) { + return null; + } + + @Override public CompleteFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request) { + return null; + } + + @Override public CompleteFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + return null; + } } From dcfa88bca8ce3cd205a74b822e90318898875589 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 11 Mar 2022 15:38:15 +0800 Subject: [PATCH 005/338] [ISSUE #3949] Init proxyStartup. --- .../rocketmq/proxy/HealthCheckServer.java | 56 ++++++++ .../apache/rocketmq/proxy/ProxyStartup.java | 125 ++++++++++++++++++ .../proxy/configuration/ProxyConfig.java | 57 +++++++- .../rocketmq/proxy/grpc/GrpcServer.java | 10 +- .../proxy/grpc/common/StartAndShutdown.java | 24 ++++ .../grpc/service/ClusterGrpcService.java | 20 ++- .../proxy/grpc/service/GrpcService.java | 3 +- .../proxy/grpc/service/LocalGrpcService.java | 8 ++ 8 files changed, 295 insertions(+), 8 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java new file mode 100644 index 0000000000..60a971f102 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.common.StartAndShutdown; + +public class HealthCheckServer implements StartAndShutdown { + + private HttpServer healthChecker; + + @Override + public void start() throws Exception { + this.healthChecker = HttpServer.create(new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0); + this.healthChecker.createContext("/status", new HealthCheckHandler()); + this.healthChecker.setExecutor(null); + this.healthChecker.start(); + } + + @Override + public void shutdown() { + this.healthChecker.stop(0); + } + + static class HealthCheckHandler implements HttpHandler { + @Override + public void handle(HttpExchange t) throws IOException { + String response = "Hello"; + t.sendResponseHeaders(200, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java new file mode 100644 index 0000000000..b89627fa19 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -0,0 +1,125 @@ +/* + * 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; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.core.joran.spi.JoranException; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.BrokerStartup; +import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.configuration.ProxyConfig; +import org.apache.rocketmq.proxy.grpc.GrpcServer; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; +import org.apache.rocketmq.proxy.grpc.service.GrpcService; +import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyStartup { + + private static final Logger log = LoggerFactory.getLogger(ProxyStartup.class); + + public static void main(String[] args) { + try { + ConfigurationManager.initEnv(); + initLogger(); + ConfigurationManager.intConfig(); + + // init thread pool monitor for proxy. + initThreadPoolMonitor(); + + // create and start grpcServer + GrpcServer grpcServer = createGrpcServer(); + grpcServer.start(); + + // health check server + final HealthCheckServer healthCheckServer = new HealthCheckServer(); + healthCheckServer.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + log.info("try to shutdown server"); + + try { + healthCheckServer.shutdown(); + Thread.sleep(TimeUnit.SECONDS.toMillis(ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds())); + } catch (Exception e) { + log.error("err when shutdown healthCheckServer", e); + } + + try { + grpcServer.shutdown(); + } catch (Exception e) { + log.error("err when shutdown grpc server", e); + } + })); + } catch (Exception e) { + System.err.println("find a unexpect err." + e); + e.printStackTrace(); + log.error("find a unexpect err.", e); + System.exit(1); + } + + System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); + log.info(new Date() + "rmq-proxy startup successfully"); + } + + private static GrpcServer createGrpcServer() throws RuntimeException { + GrpcService grpcService; + String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); + if (ProxyMode.isClusterMode(proxyModeStr)) { + grpcService = new ClusterGrpcService(); + } else if (ProxyMode.isLocalMode(proxyModeStr)) { + BrokerController brokerController = createBrokerController(); + grpcService = new LocalGrpcService(brokerController); + } else { + throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); + } + + return new GrpcServer(grpcService); + + } + + private static BrokerController createBrokerController() { + String[] brokerStartupArgs = new String[] {"-c", ConfigurationManager.getProxyConfig().getBrokerConfigPath()}; + return BrokerStartup.createBrokerController(brokerStartupArgs); + } + + private static void initThreadPoolMonitor() { + ThreadPoolMonitor.init(); + ProxyConfig config = ConfigurationManager.getProxyConfig(); + ThreadPoolMonitor.config(config.isEnablePrintJstack(), config.getPrintJstackPeriodMillis()); + } + + private static void initLogger() throws JoranException { + System.setProperty(ClientLogger.CLIENT_LOG_USESLF4J, "true"); + + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + JoranConfigurator configurator = new JoranConfigurator(); + configurator.setContext(lc); + lc.reset(); + //https://logback.qos.ch/manual/configuration.html + lc.setPackagingDataEnabled(false); + configurator.doConfigure(ConfigurationManager.getProxyHome() + "/conf/logback.xml"); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java index c0aa518caa..58a8a2537a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -22,24 +22,69 @@ import org.apache.rocketmq.proxy.grpc.common.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; + /** + * Configuration for proxy + */ + private Integer healthCheckPort = 8000; + private long waitAfterStopHealthCheckInSeconds = 40; + + /** + * configuration for ThreadPoolMonitor + */ + private boolean enablePrintJstack = true; + private long printJstackPeriodMillis = 60000; + /** * gRPC */ private String proxyMode = ProxyMode.CLUSTER.name(); private Boolean startGrpcServer = true; private Integer grpcServerPort = 8081; - private String grpcTlsKeyPath = "/home/admin/rmq-gateway/conf/tls/gRPC.key.pem"; - private String grpcTlsCertPath = "/home/admin/rmq-gateway/conf/tls/gRPC.chain.cert.pem"; + private String grpcTlsKeyPath = ConfigurationManager.getProxyHome() + "/conf/tls/gRPC.key.pem"; + private String grpcTlsCertPath = ConfigurationManager.getProxyHome() + "/conf/tls/gRPC.chain.cert.pem"; private int grpcBossLoopNum = 1; private int grpcWorkerLoopNum = Runtime.getRuntime().availableProcessors() * 2; private int grpcThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2; private int grpcThreadPoolQueueCapacity = 100000; + private String brokerConfigPath = ConfigurationManager.getProxyHome() + "/conf/broker.conf"; /** * gRPC max message size * 130M = 4M * 32 messages + 2M attributes */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; + public Integer getHealthCheckPort() { + return healthCheckPort; + } + + public void setHealthCheckPort(Integer healthCheckPort) { + this.healthCheckPort = healthCheckPort; + } + + public long getWaitAfterStopHealthCheckInSeconds() { + return waitAfterStopHealthCheckInSeconds; + } + + public void setWaitAfterStopHealthCheckInSeconds(long waitAfterStopHealthCheckInSeconds) { + this.waitAfterStopHealthCheckInSeconds = waitAfterStopHealthCheckInSeconds; + } + + public boolean isEnablePrintJstack() { + return enablePrintJstack; + } + + public void setEnablePrintJstack(boolean enablePrintJstack) { + this.enablePrintJstack = enablePrintJstack; + } + + public long getPrintJstackPeriodMillis() { + return printJstackPeriodMillis; + } + + public void setPrintJstackPeriodMillis(long printJstackPeriodMillis) { + this.printJstackPeriodMillis = printJstackPeriodMillis; + } + public String getProxyMode() { return proxyMode; } @@ -112,6 +157,14 @@ public class ProxyConfig { this.grpcThreadPoolQueueCapacity = grpcThreadPoolQueueCapacity; } + public String getBrokerConfigPath() { + return brokerConfigPath; + } + + public void setBrokerConfigPath(String brokerConfigPath) { + this.brokerConfigPath = brokerConfigPath; + } + public int getGrpcMaxInboundMessageSize() { return grpcMaxInboundMessageSize; } 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 a0aa501def..3a522a47f9 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 @@ -42,8 +42,10 @@ public class GrpcServer { private final io.grpc.Server server; private final ThreadPoolExecutor executor; + private final GrpcService grpcService; public GrpcServer(GrpcService grpcService) { + this.grpcService = grpcService; int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(port); @@ -98,7 +100,11 @@ public class GrpcServer { bossLoopNum, workerLoopNum, maxInboundMessageSize); } + public void start() throws Exception { + // first to start grpc service. + this.grpcService.start(); + this.server.start(); log.info("grpc server has started"); } @@ -108,8 +114,10 @@ public class GrpcServer { this.server.shutdown().awaitTermination(30, TimeUnit.SECONDS); this.executor.shutdown(); + this.grpcService.shutdown(); + log.info("grpc server has stopped"); - } catch (InterruptedException e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java new file mode 100644 index 0000000000..ebce8dc5f6 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java @@ -0,0 +1,24 @@ +/* + * 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.grpc.common; + +public interface StartAndShutdown { + void start() throws Exception; + + void shutdown() throws Exception; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index a49a2ecb6a..f67e0d6ec8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -64,19 +64,23 @@ public class ClusterGrpcService implements GrpcService { } - @Override public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { + @Override + public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { return null; } - @Override public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { + @Override + public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { return null; } - @Override public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { + @Override + public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { return null; } - @Override public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + @Override + public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { return null; } @@ -138,4 +142,12 @@ public class ClusterGrpcService implements GrpcService { ChangeInvisibleDurationRequest request) { return null; } + + @Override + public void start() throws Exception { + } + + @Override + public void shutdown() throws Exception { + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java index 9666eeddba..8a9aac74f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java @@ -53,8 +53,9 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import io.netty.util.concurrent.CompleteFuture; +import org.apache.rocketmq.proxy.grpc.common.StartAndShutdown; -public interface GrpcService { +public interface GrpcService extends StartAndShutdown { CompleteFuture queryRoute(Context ctx, QueryRouteRequest request); CompleteFuture heartbeat(Context ctx, HeartbeatRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 348d94d6f8..f4f03ade44 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -140,4 +140,12 @@ public class LocalGrpcService implements GrpcService { ChangeInvisibleDurationRequest request) { return null; } + + @Override public void start() throws Exception { + this.brokerController.start(); + } + + @Override public void shutdown() throws Exception { + this.brokerController.shutdown(); + } } From 876f31c31bfc1341bb20c59060566264af921f25 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 11 Mar 2022 18:08:48 +0800 Subject: [PATCH 006/338] [ISSUE #3949] Add UT for configuration package. --- .../configuration/ConfigurationManager.java | 4 +- .../proxy/grpc/common/StartAndShutdown.java | 1 - .../ConfigurationManagerTest.java | 74 +++++++++++++++++++ .../resources/rmq-proxy-home/conf/broker.conf | 22 ++++++ .../rmq-proxy-home/conf/rmq-proxy.json | 3 + 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java create mode 100644 proxy/src/test/resources/rmq-proxy-home/conf/broker.conf create mode 100644 proxy/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java index 2ee1a61f04..79617e9686 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java @@ -21,8 +21,8 @@ import java.io.File; import org.apache.commons.lang3.StringUtils; public class ConfigurationManager { - private static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; - private static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; + protected static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; + protected static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; private static String proxyHome; private static Configuration configuration; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java index ebce8dc5f6..aa0ea6809a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java @@ -19,6 +19,5 @@ package org.apache.rocketmq.proxy.grpc.common; public interface StartAndShutdown { void start() throws Exception; - void shutdown() throws Exception; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java new file mode 100644 index 0000000000..55da886530 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java @@ -0,0 +1,74 @@ +/* + * 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.configuration; + +import java.net.URL; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; +import static org.assertj.core.api.Assertions.assertThat; + +public class ConfigurationManagerTest { + public String mockProxyHome = "/mock/rmq/proxy/home"; + + @Before + public void before() throws Exception { + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + } + + @After + public void after() { + System.clearProperty(RMQ_PROXY_HOME); + } + + @Test + public void testInitEnv() { + // configure proxy home by system env. + assertThat(ConfigurationManager.getProxyHome()).isEqualTo(mockProxyHome); + } + + @Test + public void testIntConfig() { + assertThat(ConfigurationManager.getProxyConfig()).isNotNull(); + assertThat(ConfigurationManager.getProxyConfig().getProxyMode()).isEqualToIgnoringCase(ProxyMode.CLUSTER.toString()); + + String brokerConfig = ConfigurationManager.getProxyConfig().getBrokerConfigPath(); + assertThat(brokerConfig).isEqualTo(ConfigurationManager.getProxyHome() + "/conf/broker.conf"); + } + + @Test + public void testGetProxyHome() { + // test configured proxy home + assertThat(ConfigurationManager.getProxyHome()).isEqualTo(mockProxyHome); + } + + @Test + public void testGetProxyConfig() { + assertThat(ConfigurationManager.getProxyConfig()).isNotNull(); + } + +} diff --git a/proxy/src/test/resources/rmq-proxy-home/conf/broker.conf b/proxy/src/test/resources/rmq-proxy-home/conf/broker.conf new file mode 100644 index 0000000000..0c0b28b7b8 --- /dev/null +++ b/proxy/src/test/resources/rmq-proxy-home/conf/broker.conf @@ -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. + +brokerClusterName = DefaultCluster +brokerName = broker-a +brokerId = 0 +deleteWhen = 04 +fileReservedTime = 48 +brokerRole = ASYNC_MASTER +flushDiskType = ASYNC_FLUSH diff --git a/proxy/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json b/proxy/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json new file mode 100644 index 0000000000..f0873e2a35 --- /dev/null +++ b/proxy/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json @@ -0,0 +1,3 @@ +{ + "proxyMode": "cluster" +} \ No newline at end of file From 763e874b2083aa107187d06f91089347b8c35608 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 14 Mar 2022 16:18:47 +0800 Subject: [PATCH 007/338] [ISSUE #3949] can config bootstrap thread num; disable callbackExecutor and nettyWorkerGroup in NettyClientConfig --- .../rocketmq/remoting/netty/NettyClientConfig.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java index 2f123db45e..cb8c9a1844 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.remoting.netty; public class NettyClientConfig { + private int bootstrapWorkerThreads = 1; /** * Worker thread number */ @@ -43,11 +44,19 @@ public class NettyClientConfig { private boolean useTLS; + private boolean disableCallbackExecutor = false; + private boolean disableNettyWorkerGroup = false; + private int writeBufferHighWaterMark = NettySystemConfig.writeBufferHighWaterMark; private int writeBufferLowWaterMark = NettySystemConfig.writeBufferLowWaterMark; - private boolean disableCallbackExecutor = false; - private boolean disableNettyWorkerGroup = false; + public int getBootstrapWorkerThreads() { + return bootstrapWorkerThreads; + } + + public void setBootstrapWorkerThreads(int bootstrapWorkerThreads) { + this.bootstrapWorkerThreads = bootstrapWorkerThreads; + } public boolean isClientCloseSocketIfTimeout() { return clientCloseSocketIfTimeout; From ca3de6a315c42d5882c26d90085088abfb6ae5a5 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 14 Mar 2022 16:21:54 +0800 Subject: [PATCH 008/338] [ISSUE #3949] add client for proxy in cluster mode --- .../client/impl/MQClientAPIExtImpl.java | 296 ++++++++++++++++++ .../rocketmq/client/impl/MQClientAPIImpl.java | 2 +- proxy/pom.xml | 20 +- .../rocketmq/proxy/HealthCheckServer.java | 2 +- .../rocketmq/proxy/client/BaseClient.java | 59 ++++ .../rocketmq/proxy/client/ClientFactory.java | 77 +++++ .../rocketmq/proxy/client/ClientManager.java | 67 ++++ .../rocketmq/proxy/client/DefaultClient.java | 62 ++++ .../rocketmq/proxy/client/ProducerClient.java | 67 ++++ .../proxy/client/ReadConsumerClient.java | 62 ++++ .../proxy/client/TopicRouteCache.java | 132 ++++++++ .../proxy/client/WriteConsumerClient.java | 68 ++++ .../AbstractRocketMQClientConstructor.java | 85 +++++ .../mqconstructor/MQClientAPIConstructor.java | 49 +++ .../RocketMQClientConstructor.java | 24 ++ .../TransactionClientConstructor.java | 49 +++ .../DoNothingClientRemotingProcessor.java | 35 +++ .../ProxyClientRemotingProcessor.java | 76 +++++ .../client/route/AddressableMessageQueue.java | 80 +++++ .../client/route/MessageQueueWrapper.java | 55 ++++ .../client/route/SelectableMessageQueue.java | 244 +++++++++++++++ .../proxy/client/route/TopicRouteWrapper.java | 72 +++++ .../client/transaction/TransactionId.java | 226 +++++++++++++ .../TransactionStateCheckRequest.java | 86 +++++ .../transaction/TransactionStateChecker.java | 22 ++ .../common/AbstractStartAndShutdown.java | 45 +++ .../proxy/common/RetainCacheLoader.java | 53 ++++ .../rocketmq/proxy/common/RocketMQHelper.java | 52 +++ .../{grpc => }/common/StartAndShutdown.java | 2 +- .../proxy/common/utils/ProxyUtils.java | 24 ++ .../proxy/configuration/ProxyConfig.java | 147 +++++++++ .../proxy/grpc/service/GrpcService.java | 2 +- 32 files changed, 2330 insertions(+), 12 deletions(-) create mode 100644 client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc => }/common/StartAndShutdown.java (95%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java new file mode 100644 index 0000000000..d3713c58cb --- /dev/null +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -0,0 +1,296 @@ +/* + * 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.impl; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.consumer.AckCallback; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopCallback; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PullCallback; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.RemotingClient; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; +import org.apache.rocketmq.remoting.netty.ResponseFuture; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class MQClientAPIExtImpl { + + private final MQClientAPIImpl mqClientAPI; + private final ClientConfig clientConfig; + + public MQClientAPIExtImpl(NettyClientConfig nettyClientConfig, + ClientRemotingProcessor clientRemotingProcessor, + RPCHook rpcHook, ClientConfig clientConfig) { + this.clientConfig = clientConfig; + this.mqClientAPI = new MQClientAPIImpl(nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig); + } + + public void start() { + this.mqClientAPI.start(); + } + + public void shutdown() { + this.mqClientAPI.shutdown(); + } + + 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("unknow reseaon", responseFuture.getCause()); + } + return ex; + } + + protected RemotingClient getRemotingClient() { + return this.mqClientAPI.getRemotingClient(); + } + + public CompletableFuture sendHeartbeat(String brokerAddr, HeartbeatData heartbeatData, + long timeoutMillis) { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); + 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; + } + + public CompletableFuture sendMessage(String brokerAddr, String brokerName, Message msg, + SendMessageRequestHeader requestHeader, long timeoutMillis) { + + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); + 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(mqClientAPI.processSendResponse(brokerName, msg, response, brokerAddr)); + } catch (Exception e) { + future.completeExceptionally(e); + } + } else { + future.completeExceptionally(processNullResponseErr(responseFuture)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture sendMessageBack(String brokerAddr, + ConsumerSendMsgBackRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand request = RemotingCommand.createResponseCommandWithHeader(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + 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; + } + + public CompletableFuture popMessage(String brokerAddr, String brokerName, + PopMessageRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.mqClientAPI.popMessageAsync(brokerAddr, brokerName, requestHeader, timeoutMillis, new PopCallback() { + @Override + public void onSuccess(PopResult popResult) { + future.complete(popResult); + } + + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture ackMessage(String brokerAddr, AckMessageRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.mqClientAPI.ackMessageAsync(brokerAddr, timeoutMillis, new AckCallback() { + @Override + public void onSuccess(AckResult ackResult) { + future.complete(ackResult); + } + + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } + }, requestHeader); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture changeInvisibleTimeAsync(String brokerAddr, String brokerName, + ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.mqClientAPI.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new AckCallback() { + @Override + public void onSuccess(AckResult ackResult) { + future.complete(ackResult); + } + + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture pullMessage(String brokerAddr, PullMessageRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.mqClientAPI.pullMessage(brokerAddr, requestHeader, timeoutMillis, CommunicationMode.ASYNC, new PullCallback() { + @Override + public void onSuccess(PullResult pullResult) { + future.complete(pullResult); + } + + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public void updateConsumerOffsetOneWay(String brokerAddr, UpdateConsumerOffsetRequestHeader header, + long timeoutMillis) throws InterruptedException, RemotingException { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONSUMER_OFFSET, header); + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + } + + public CompletableFuture> getConsumerListByGroup(String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, + long timeoutMillis) { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_LIST_BY_GROUP, requestHeader); + + CompletableFuture> future = new CompletableFuture<>(); + try { + this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { + RemotingCommand response = responseFuture.getResponseCommand(); + if (response != null) { + switch (response.getCode()) { + case ResponseCode.SUCCESS: { + if (response.getBody() != null) { + GetConsumerListByGroupResponseBody body = + GetConsumerListByGroupResponseBody.decode(response.getBody(), GetConsumerListByGroupResponseBody.class); + future.complete(body.getConsumerIdList()); + return; + } + } + /** + * @see org.apache.rocketmq.broker.processor.ConsumerManageProcessor#getConsumerListByGroup, + * broker will return {@link ResponseCode.SYSTEM_ERROR} if there is no consumer. + */ + case ResponseCode.SYSTEM_ERROR: { + future.complete(Collections.emptyList()); + return; + } + default: + break; + } + future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark())); + } else { + future.completeExceptionally(processNullResponseErr(responseFuture)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { + return this.mqClientAPI.getTopicRouteInfoFromNameServer(topic, timeoutMillis); + } +} 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 15b32d8505..765184478f 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 @@ -740,7 +740,7 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { } } - private SendResult processSendResponse( + protected SendResult processSendResponse( final String brokerName, final Message msg, final RemotingCommand response, diff --git a/proxy/pom.xml b/proxy/pom.xml index b2d0759faf..b38e097333 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -41,6 +41,18 @@ rocketmq-proto 5.0.0-SNAPSHOT + + org.apache.rocketmq + rocketmq-broker + + + org.apache.rocketmq + rocketmq-common + + + org.apache.rocketmq + rocketmq-client + io.grpc grpc-netty-shaded @@ -61,14 +73,6 @@ com.google.protobuf protobuf-java-util - - org.apache.rocketmq - rocketmq-broker - - - org.apache.rocketmq - rocketmq-common - org.apache.commons commons-lang3 diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java index 60a971f102..124bc282b2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -24,7 +24,7 @@ import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.common.StartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; public class HealthCheckServer implements StartAndShutdown { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java new file mode 100644 index 0000000000..270e1ae825 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import java.util.concurrent.ThreadLocalRandom; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.proxy.common.StartAndShutdown; + +public abstract class BaseClient implements StartAndShutdown { + + private final ClientFactory clientFactory; + private MQClientAPIExtImpl[] clients; + + public BaseClient(ClientFactory clientFactory) { + this.clientFactory = clientFactory; + } + + protected abstract int getClientNum(); + + protected abstract MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name); + + protected abstract String getNamePrefix(); + + protected MQClientAPIExtImpl getClient() { + if (clients.length == 1) { + return this.clients[0]; + } + return this.clients[ThreadLocalRandom.current().nextInt(this.clients.length)]; + } + + @Override + public void start() throws Exception { + int clientCount = getClientNum(); + this.clients = new MQClientAPIExtImpl[clientCount]; + for (int i = 0; i < clientCount; i++) { + String name = getNamePrefix() + "N_" + i; + clients[i] = createNewClient(clientFactory, name); + } + } + + @Override + public void shutdown() throws Exception { + + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java new file mode 100644 index 0000000000..5e777eef30 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java @@ -0,0 +1,77 @@ +/* + * 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.client; + +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.proxy.client.mqconstructor.MQClientAPIConstructor; +import org.apache.rocketmq.proxy.client.mqconstructor.TransactionClientConstructor; +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.remoting.RPCHook; + +public class ClientFactory implements StartAndShutdown { + + private RPCHook rpcHook = null; + + private final MQClientAPIConstructor mqClientAPIConstructor; + private final TransactionClientConstructor transactionClientConstructor; + + public ClientFactory(TransactionStateChecker transactionStateChecker) { + this.init(); + + this.mqClientAPIConstructor = new MQClientAPIConstructor(this.rpcHook); + this.transactionClientConstructor = new TransactionClientConstructor(this.rpcHook); + } + + private void init() { + System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, + System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); + if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvAddr())) { + System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, ConfigurationManager.getProxyConfig().getNameSrvAddr()); + } else { + System.setProperty("rocketmq.namesrv.domain", ConfigurationManager.getProxyConfig().getNameSrvDomain()); + System.setProperty("rocketmq.namesrv.domain.subgroup", ConfigurationManager.getProxyConfig().getNameSrvDomainSubgroup()); + } + } + + public MQClientAPIExtImpl getMQClient(String instanceName, int bootstrapWorkerThreads) { + return mqClientAPIConstructor.getOne(instanceName, bootstrapWorkerThreads); + } + + public MQClientAPIExtImpl getTransactionClient(String instanceName, int bootstrapWorkerThreads) { + return transactionClientConstructor.getOne(instanceName, bootstrapWorkerThreads); + } + + public void setRpcHook(RPCHook rpcHook) { + this.rpcHook = rpcHook; + } + + @Override + public void start() throws Exception { + + } + + @Override + public void shutdown() throws Exception { + this.mqClientAPIConstructor.shutdownAll(); + this.transactionClientConstructor.shutdownAll(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java new file mode 100644 index 0000000000..8850da5f5c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; + +public class ClientManager extends AbstractStartAndShutdown { + + private final ClientFactory clientFactory; + private final DefaultClient defaultClient; + private final ProducerClient producerClient; + private final ReadConsumerClient readConsumerClient; + private final WriteConsumerClient writeConsumerClient; + + private final TopicRouteCache topicRouteCache; + + public ClientManager(TransactionStateChecker transactionStateChecker) { + this.clientFactory = new ClientFactory(transactionStateChecker); + this.defaultClient = new DefaultClient(this.clientFactory); + this.producerClient = new ProducerClient(this.clientFactory); + this.readConsumerClient = new ReadConsumerClient(this.clientFactory); + this.writeConsumerClient = new WriteConsumerClient(this.clientFactory); + + this.topicRouteCache = new TopicRouteCache(this.defaultClient); + + this.appendStartAndShutdown(this.clientFactory) + .appendStartAndShutdown(this.defaultClient) + .appendStartAndShutdown(this.producerClient) + .appendStartAndShutdown(this.readConsumerClient) + .appendStartAndShutdown(this.writeConsumerClient); + } + + public DefaultClient getDefaultClient() { + return defaultClient; + } + + public ProducerClient getProducerClient() { + return producerClient; + } + + public ReadConsumerClient getReadConsumerClient() { + return readConsumerClient; + } + + public WriteConsumerClient getWriteConsumerClient() { + return writeConsumerClient; + } + + public TopicRouteCache getTopicRouteCache() { + return topicRouteCache; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java new file mode 100644 index 0000000000..4ab7518eb4 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.remoting.exception.RemotingException; + +public class DefaultClient extends BaseClient { + + private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; + + public DefaultClient(ClientFactory clientFactory) { + super(clientFactory); + } + + @Override + protected int getClientNum() { + return ConfigurationManager.getProxyConfig().getDefaultClientNum(); + } + + @Override + protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getDefaultClientWorkerFactor(); + final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); + + return clientFactory.getMQClient(name, threadCount); + } + + @Override + protected String getNamePrefix() { + return CID_PREFIX; + } + + public CompletableFuture> getConsumerListByGroup(String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, + long timeoutMillis) { + return getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); + } + + public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { + return getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java new file mode 100644 index 0000000000..668cb7fce8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ProducerClient extends BaseClient { + + private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; + + public ProducerClient(ClientFactory clientFactory) { + super(clientFactory); + } + + @Override + protected int getClientNum() { + return ConfigurationManager.getProxyConfig().getProducerClientNum(); + } + + @Override + protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { + double sendClientWorkerFactor = ConfigurationManager.getProxyConfig().getProducerClientWorkerFactor(); + final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * sendClientWorkerFactor); + + return clientFactory.getTransactionClient(name, threadCount); + } + + @Override + protected String getNamePrefix() { + return PID_PREFIX; + } + + public CompletableFuture heartBeat(String heartbeatAddr, HeartbeatData heartbeatData, long timeout) throws Exception { + return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); + } + + public CompletableFuture sendMessage(String address, String brokerName, Message msg, + SendMessageRequestHeader requestHeader, long timeoutMillis) { + return this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); + } + + public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { + return this.getClient().sendMessageBack(brokerAddr, requestHeader, timeoutMillis); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java new file mode 100644 index 0000000000..60516f9534 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; + +public class ReadConsumerClient extends BaseClient { + + private static final String CID_PREFIX = "CID_RMQ_PROXY_CONSUME_MESSAGE_"; + + public ReadConsumerClient(ClientFactory clientFactory) { + super(clientFactory); + } + + @Override + protected int getClientNum() { + return ConfigurationManager.getProxyConfig().getConsumerClientNum(); + } + + @Override + protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getConsumerClientWorkerFactor(); + final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); + + return clientFactory.getMQClient(name, threadCount); + } + + @Override + protected String getNamePrefix() { + return CID_PREFIX; + } + + public CompletableFuture popMessage(String address, String brokerName, PopMessageRequestHeader requestHeader, + long timeoutMillis) { + return getClient().popMessage(address, brokerName, requestHeader, timeoutMillis); + } + + public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, + long timeoutMillis) { + return getClient().pullMessage(address, requestHeader, timeoutMillis); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java new file mode 100644 index 0000000000..1e346266cd --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -0,0 +1,132 @@ +/* + * 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.client; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.common.RetainCacheLoader; +import org.apache.rocketmq.proxy.common.RocketMQHelper; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.configuration.ProxyConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopicRouteCache { + + private static final Logger log = LoggerFactory.getLogger(TopicRouteCache.class); + + private final LoadingCache topicCache; + private final ThreadPoolExecutor cacheRefreshExecutor; + + private final DefaultClient defaultClient; + + public TopicRouteCache(DefaultClient defaultClient) { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + + this.defaultClient = defaultClient; + this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( + config.getTopicRouteThreadPoolNums(), + config.getTopicRouteThreadPoolNums(), + 1000 * 60, + TimeUnit.MILLISECONDS, + "TopicRouteCacheRefresh", + config.getTopicRouteThreadPoolQueueCapacity() + ); + this.topicCache = CacheBuilder.newBuilder() + .maximumSize(config.getTopicRouteCacheMaxNum()) + .refreshAfterWrite(config.getTopicRouteCacheExpireSecond(), TimeUnit.SECONDS) + .build(new TopicRouteCacheLoader()); + } + + public MessageQueueWrapper getMessageQueue(String topicName) throws Exception { + return getCacheMessageQueueWrapper(this.topicCache, topicName); + } + + protected static MessageQueueWrapper getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { + MessageQueueWrapper res = topicCache.get(key); + if (res.isEmptyCacheQueue()) { + throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, + "No topic route info in name server for the topic: " + key); + } + return res; + } + + protected static boolean routeDataIsValid(TopicRouteData routeData) { + return routeData != null && routeData.getQueueDatas() != null && !routeData.getQueueDatas().isEmpty() + && routeData.getBrokerDatas() != null && !routeData.getBrokerDatas().isEmpty(); + } + + protected abstract class AbstractTopicRouteCacheLoader extends RetainCacheLoader { + + public AbstractTopicRouteCacheLoader() { + super(cacheRefreshExecutor); + } + + protected abstract String loaderName(); + + protected abstract TopicRouteData loadTopicRouteData(String topic) throws Exception; + + protected boolean refreshBrokerAddrTable() { + return false; + } + + @Override + public MessageQueueWrapper getDirectly(String topic) throws Exception { + try { + TopicRouteData topicRouteData = loadTopicRouteData(topic); + + if (routeDataIsValid(topicRouteData)) { + MessageQueueWrapper tmp = new MessageQueueWrapper(topic, topicRouteData); + log.info("load {} from namesrv. topic: {}, queue: {}", loaderName(), topic, tmp); + return tmp; + } + return MessageQueueWrapper.EMPTY_CACHE_QUEUES; + } catch (Exception e) { + if (RocketMQHelper.isTopicNotExistError(e)) { + return MessageQueueWrapper.EMPTY_CACHE_QUEUES; + } + throw e; + } + } + + @Override + protected void onErr(String key, Exception e) { + log.error("load {} from namesrv failed. topic:{}", loaderName(), key, e); + } + } + + protected class TopicRouteCacheLoader extends AbstractTopicRouteCacheLoader { + + @Override + protected String loaderName() { + return "topicRoute"; + } + + @Override + protected TopicRouteData loadTopicRouteData(String topic) throws Exception { + return defaultClient.getTopicRouteInfoFromNameServer(topic, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java new file mode 100644 index 0000000000..ee04262163 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.remoting.exception.RemotingException; + +public class WriteConsumerClient extends BaseClient { + + private static final String CID_PREFIX = "CID_RMQ_PROXY_DELETE_MESSAGE_"; + + public WriteConsumerClient(ClientFactory clientFactory) { + super(clientFactory); + } + + @Override + protected int getClientNum() { + return ConfigurationManager.getProxyConfig().getConsumerClientNum(); + } + + @Override + protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getConsumerClientWorkerFactor(); + final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); + + return clientFactory.getMQClient(name, threadCount); + } + + @Override + protected String getNamePrefix() { + return CID_PREFIX; + } + + public CompletableFuture ackMessage(String address, AckMessageRequestHeader requestHeader, + long timeoutMillis) { + return getClient().ackMessage(address, requestHeader, timeoutMillis); + } + + public CompletableFuture changeInvisibleTimeAsync(String address, String brokerName, + ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + return getClient().changeInvisibleTimeAsync(address, brokerName, requestHeader, timeoutMillis); + } + + public void updateConsumerOffsetOneWay(String brokerAddr, UpdateConsumerOffsetRequestHeader header, + long timeoutMillis) throws RemotingException, InterruptedException { + getClient().updateConsumerOffsetOneWay(brokerAddr, header, timeoutMillis); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java new file mode 100644 index 0000000000..4e530cacf8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java @@ -0,0 +1,85 @@ +/* + * 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.client.mqconstructor; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractRocketMQClientConstructor implements RocketMQClientConstructor { + + private static final Logger log = LoggerFactory.getLogger(AbstractRocketMQClientConstructor.class); + + protected Map cacheTable = new ConcurrentHashMap<>(); + protected RPCHook rpcHook; + + public AbstractRocketMQClientConstructor(RPCHook rpcHook) { + this.rpcHook = rpcHook; + } + + abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) throws Throwable; + + abstract boolean tryStart(T t); + + abstract void shutdown(T t); + + protected static NettyClientConfig createNettyClientConfig(int bootstrapWorkerThreads) { + NettyClientConfig nettyClientConfig = new NettyClientConfig(); + nettyClientConfig.setBootstrapWorkerThreads(bootstrapWorkerThreads); + nettyClientConfig.setDisableNettyWorkerGroup(true); + nettyClientConfig.setDisableCallbackExecutor(true); + return nettyClientConfig; + } + + @Override + public T getOne(String instanceName, int bootstrapWorkerThreads) { + if (cacheTable.containsKey(instanceName)) { + return cacheTable.get(instanceName); + } + + T object; + try { + object = this.newOne(instanceName, rpcHook, bootstrapWorkerThreads); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + T old = cacheTable.putIfAbsent(instanceName, object); + if (old == null) { + if (!this.tryStart(object)) { + return null; + } + } else { + object = old; + } + + return object; + } + + @Override + public void shutdownAll() { + this.cacheTable.forEach((k, v) -> { + try { + this.shutdown(v); + } catch (Exception e) { + log.warn("RocketMQClientConstructor shutdown all err.", e); + } + }); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java new file mode 100644 index 0000000000..b9a3773060 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client.mqconstructor; + +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.proxy.client.processor.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.remoting.RPCHook; + +public class MQClientAPIConstructor extends AbstractRocketMQClientConstructor { + + public MQClientAPIConstructor(RPCHook rpcHook) { + super(rpcHook); + } + + @Override + MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + return new MQClientAPIExtImpl( + createNettyClientConfig(bootstrapWorkerThreads), + new DoNothingClientRemotingProcessor(null), + rpcHook, + new ClientConfig()); + } + + @Override + boolean tryStart(MQClientAPIExtImpl client) { + client.start(); + return true; + } + + @Override + void shutdown(MQClientAPIExtImpl client) { + client.shutdown(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java new file mode 100644 index 0000000000..2dd0378e7e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java @@ -0,0 +1,24 @@ +/* + * 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.client.mqconstructor; + +public interface RocketMQClientConstructor { + + T getOne(String instanceName, int bootstrapWorkerThreads); + + void shutdownAll(); +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java new file mode 100644 index 0000000000..67f8fb62bd --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client.mqconstructor; + +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.proxy.client.processor.ProxyClientRemotingProcessor; +import org.apache.rocketmq.remoting.RPCHook; + +public class TransactionClientConstructor extends AbstractRocketMQClientConstructor { + + public TransactionClientConstructor(RPCHook rpcHook) { + super(rpcHook); + } + + @Override + MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + return new MQClientAPIExtImpl( + createNettyClientConfig(bootstrapWorkerThreads), + new ProxyClientRemotingProcessor(null), + rpcHook, + new ClientConfig()); + } + + @Override + boolean tryStart(MQClientAPIExtImpl client) { + client.start(); + return true; + } + + @Override + void shutdown(MQClientAPIExtImpl client) { + client.shutdown(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java new file mode 100644 index 0000000000..2f9d100f72 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client.processor; + +import io.netty.channel.ChannelHandlerContext; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.client.impl.factory.MQClientInstance; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class DoNothingClientRemotingProcessor extends ClientRemotingProcessor { + + public DoNothingClientRemotingProcessor( + MQClientInstance mqClientFactory) { + super(mqClientFactory); + } + + @Override + public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) { + return null; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java new file mode 100644 index 0000000000..07361919b0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java @@ -0,0 +1,76 @@ +/* + * 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.client.processor; + +import io.netty.channel.ChannelHandlerContext; +import java.nio.ByteBuffer; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.proxy.client.transaction.TransactionId; +import org.apache.rocketmq.proxy.client.transaction.TransactionStateCheckRequest; +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { + + private final TransactionStateChecker transactionStateChecker; + + public ProxyClientRemotingProcessor( + TransactionStateChecker transactionStateChecker) { + super(null); + this.transactionStateChecker = transactionStateChecker; + } + + @Override + public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { + if (request.getCode() == RequestCode.CHECK_TRANSACTION_STATE) { + return this.checkTransactionState(ctx, request); + } + return null; + } + + @Override + public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, + RemotingCommand request) throws RemotingCommandException { + final CheckTransactionStateRequestHeader requestHeader = (CheckTransactionStateRequestHeader) request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + final ByteBuffer byteBuffer = ByteBuffer.wrap(request.getBody()); + final MessageExt messageExt = MessageDecoder.decode(byteBuffer, true, false, false); + if (messageExt != null) { + final String group = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); + if (group != null) { + transactionStateChecker.checkTransactionState(new TransactionStateCheckRequest( + group, + requestHeader.getTranStateTableOffset(), + requestHeader.getCommitLogOffset(), + requestHeader.getMsgId(), + TransactionId.genFromBrokerTransactionId( + ctx.channel().remoteAddress(), + requestHeader.getTransactionId(), + requestHeader.getCommitLogOffset(), + requestHeader.getTranStateTableOffset()), + messageExt + )); + } + } + return null; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java new file mode 100644 index 0000000000..ee6db196e3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.client.route; + +import java.util.Objects; +import org.apache.rocketmq.common.message.MessageQueue; + +public class AddressableMessageQueue implements Comparable { + + private final MessageQueue messageQueue; + private final String brokerAddr; + + public AddressableMessageQueue(MessageQueue messageQueue, String brokerAddr) { + this.messageQueue = messageQueue; + this.brokerAddr = brokerAddr; + } + + @Override + public int compareTo(AddressableMessageQueue o) { + return messageQueue.compareTo(o.messageQueue); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AddressableMessageQueue)) { + return false; + } + AddressableMessageQueue queue = (AddressableMessageQueue) o; + return Objects.equals(messageQueue, queue.messageQueue); + } + + @Override + public int hashCode() { + return messageQueue == null ? 1 : messageQueue.hashCode(); + } + + public int getQueueId() { + return this.messageQueue.getQueueId(); + } + + public String getBrokerName() { + return this.messageQueue.getBrokerName(); + } + + public String getTopic() { + return messageQueue.getTopic(); + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + public String getBrokerAddr() { + return brokerAddr; + } + + @Override public String toString() { + return "AddressableMessageQueue{" + + "messageQueue=" + messageQueue + + ", brokerAddr='" + brokerAddr + '\'' + + '}'; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java new file mode 100644 index 0000000000..bfffbe31cc --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java @@ -0,0 +1,55 @@ +/* + * 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.client.route; + +import org.apache.rocketmq.common.protocol.route.TopicRouteData; + +public class MessageQueueWrapper { + public static final MessageQueueWrapper EMPTY_CACHE_QUEUES = new MessageQueueWrapper("", new TopicRouteData()); + + private final SelectableMessageQueue read; + private final SelectableMessageQueue write; + private final TopicRouteWrapper topicRouteWrapper; + + public MessageQueueWrapper(String topic, TopicRouteData topicRouteData) { + this.topicRouteWrapper = new TopicRouteWrapper(topicRouteData, topic); + + this.read = new SelectableMessageQueue(topicRouteWrapper, true); + this.write = new SelectableMessageQueue(topicRouteWrapper, false); + } + + public TopicRouteData getTopicRouteData() { + return topicRouteWrapper.getTopicRouteData(); + } + + public String getTopicName() { + return topicRouteWrapper.getTopicName(); + } + + public boolean isEmptyCacheQueue() { + return this == EMPTY_CACHE_QUEUES; + } + + @Override + public String toString() { + return "MessageQueueWrapper{" + + "read=" + read + + ", write=" + write + + ", topicRouteWrapper=" + topicRouteWrapper + + '}'; + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java new file mode 100644 index 0000000000..1ed80ff522 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java @@ -0,0 +1,244 @@ +/* + * 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.client.route; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.route.QueueData; + +public class SelectableMessageQueue { + + // queueId : normal + private final List queues; + // queueId : -1 + private final List brokers; + private final Map brokerNameMap; + private final AtomicInteger queueIndex; + private final AtomicInteger brokerIndex; + + public SelectableMessageQueue(TopicRouteWrapper topicRouteWrapper, boolean read) { + this.queues = new ArrayList<>(); + this.brokers = new ArrayList<>(); + this.brokerNameMap = new HashMap<>(); + if (read) { + this.queues.addAll(buildRead(topicRouteWrapper)); + } else { + this.queues.addAll(buildWrite(topicRouteWrapper)); + } + buildBroker(topicRouteWrapper.getTopicName(), this.queues); + + this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + this.brokerIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + } + + private static List buildRead( + TopicRouteWrapper topicRoute) { + List queues = new ArrayList<>(); + List qds = topicRoute.getQueueDatas(); + if (qds == null) { + return queues; + } + Collections.sort(qds); + for (QueueData qd : qds) { + if (PermName.isReadable(qd.getPerm())) { + String brokerAddr = topicRoute.getMasterAddrPrefer(qd.getBrokerName()); + if (brokerAddr == null) { + continue; + } + + for (int i = 0; i < qd.getReadQueueNums(); i++) { + AddressableMessageQueue mq = new AddressableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), + brokerAddr); + if (!queues.contains(mq)) { + queues.add(mq); + } + } + } + } + + Collections.sort(queues); + return queues; + } + + private static List buildWrite( + TopicRouteWrapper topicRoute) { + List queues = new ArrayList<>(); + // order topic route. + if (StringUtils.isNotBlank(topicRoute.getOrderTopicConf())) { + String[] brokers = topicRoute.getOrderTopicConf().split(";"); + for (String broker : brokers) { + String[] item = broker.split(":"); + String brokerName = item[0]; + String brokerAddr = topicRoute.getMasterAddr(brokerName); + if (brokerAddr == null) { + continue; + } + + int nums = Integer.parseInt(item[1]); + for (int i = 0; i < nums; i++) { + AddressableMessageQueue mq = new AddressableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), brokerName, i), + brokerAddr); + if (!queues.contains(mq)) { + queues.add(mq); + } + } + } + } else { + List qds = topicRoute.getQueueDatas(); + if (qds == null) { + return queues; + } + Collections.sort(qds); + for (QueueData qd : qds) { + if (PermName.isWriteable(qd.getPerm())) { + String brokerName = qd.getBrokerName(); + String brokerAddr = topicRoute.getMasterAddr(brokerName); + if (brokerAddr == null) { + continue; + } + + for (int i = 0; i < qd.getWriteQueueNums(); i++) { + AddressableMessageQueue mq = new AddressableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), brokerName, i), + brokerAddr); + if (!queues.contains(mq)) { + queues.add(mq); + } + } + } + } + } + + Collections.sort(queues); + return queues; + } + + private void buildBroker(String topic, List queues) { + for (AddressableMessageQueue messageQueue : queues) { + AddressableMessageQueue mb = new AddressableMessageQueue( + new MessageQueue(topic, messageQueue.getMessageQueue().getBrokerName(), -1), + messageQueue.getBrokerAddr()); + if (!brokers.contains(mb)) { + brokers.add(mb); + brokerNameMap.put(mb.getBrokerName(), mb); + } + } + + Collections.sort(brokers); + } + + public final AddressableMessageQueue getBrokerByName(String brokerName) { + return this.brokerNameMap.get(brokerName); + } + + public final AddressableMessageQueue selectOne(boolean onlyBroker) { + return selectOneByIndex(onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(), onlyBroker); + } + + public final AddressableMessageQueue selectOne(String brokerName, int queueId) { + for (AddressableMessageQueue addressableMessageQueue : queues) { + String queueBrokerName = addressableMessageQueue.getBrokerName(); + if (queueBrokerName.equals(brokerName) && addressableMessageQueue.getQueueId() == queueId) { + return addressableMessageQueue; + } + } + return null; + } + + public final AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { + if (onlyBroker) { + if (brokers.isEmpty()) { + return null; + } + return brokers.get(Math.abs(index) % brokers.size()); + } + if (queues.isEmpty()) { + return null; + } + return queues.get(Math.abs(index) % queues.size()); + } + + public final AddressableMessageQueue selectNextOne( + AddressableMessageQueue last) { + boolean onlyBroker = last.getQueueId() < 0; + AddressableMessageQueue newOne = last; + int count = onlyBroker ? brokers.size() : queues.size(); + + for (int i = 0; i < count; i++) { + newOne = selectOne(onlyBroker); + if (!newOne.getBrokerName().equals(last.getBrokerName()) || newOne.getQueueId() != last.getQueueId()) { + break; + } + } + + return newOne; + } + + public final AddressableMessageQueue selectNextBrokerOne( + AddressableMessageQueue last) { + boolean onlyBroker = last.getQueueId() < 0; + AddressableMessageQueue newOne = last; + int count = onlyBroker ? brokers.size() : queues.size(); + + for (int i = 0; i < count; i++) { + newOne = selectOne(onlyBroker); + if (!newOne.getBrokerName().equals(last.getBrokerName())) { + break; + } + } + + return newOne; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SelectableMessageQueue)) { + return false; + } + SelectableMessageQueue queue = (SelectableMessageQueue) o; + return Objects.equals(queues, queue.queues) && + Objects.equals(brokers, queue.brokers); + } + + @Override + public int hashCode() { + return Objects.hash(queues, brokers); + } + + @Override + public String toString() { + return "SelectableMessageQueue{" + "queues=" + queues + + ", brokers=" + brokers + + ", queueIndex=" + queueIndex + + ", brokerIndex=" + brokerIndex + + '}'; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java new file mode 100644 index 0000000000..951ca5c5b7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java @@ -0,0 +1,72 @@ +/* + * 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.client.route; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; + +public class TopicRouteWrapper { + + private final TopicRouteData topicRouteData; + private final String topicName; + private final Map brokerNameRouteData = new HashMap<>(); + + public TopicRouteWrapper(TopicRouteData topicRouteData, String topicName) { + this.topicRouteData = topicRouteData; + this.topicName = topicName; + + for (BrokerData brokerData : this.topicRouteData.getBrokerDatas()) { + brokerNameRouteData.put(brokerData.getBrokerName(), brokerData); + } + } + + public String getMasterAddr(String brokerName) { + return brokerNameRouteData.get(brokerName).getBrokerAddrs().get(MixAll.MASTER_ID); + } + + public String getMasterAddrPrefer(String brokerName) { + HashMap brokerAddr = brokerNameRouteData.get(brokerName).getBrokerAddrs(); + String addr = brokerAddr.get(MixAll.MASTER_ID); + if (addr == null) { + Optional optional = brokerAddr.keySet().stream().findFirst(); + return optional.map(brokerAddr::get).orElse(null); + } + return addr; + } + + public String getTopicName() { + return topicName; + } + + public TopicRouteData getTopicRouteData() { + return topicRouteData; + } + + public List getQueueDatas() { + return this.topicRouteData.getQueueDatas(); + } + + public String getOrderTopicConf() { + return this.topicRouteData.getOrderTopicConf(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java new file mode 100644 index 0000000000..3c5b06de72 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java @@ -0,0 +1,226 @@ +/* + * 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.client.transaction; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageId; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionId { + private static final Logger log = LoggerFactory.getLogger(TransactionId.class); + + private SocketAddress brokerAddr; + private String brokerTransactionId; + private long commitLogOffset; + private long tranStateTableOffset; + private String gatewayTransactionId; + + public TransactionId(SocketAddress brokerAddr, String brokerTransactionId, long commitLogOffset, + long tranStateTableOffset, String gatewayTransactionId) { + this.brokerAddr = brokerAddr; + this.brokerTransactionId = brokerTransactionId; + this.commitLogOffset = commitLogOffset; + this.tranStateTableOffset = tranStateTableOffset; + this.gatewayTransactionId = gatewayTransactionId; + } + + public TransactionId() { + } + + public static TransactionId genFromBrokerTransactionId(String brokerAddr, SendResult sendResult) { + MessageId id = new MessageId(null, 0); + try { + if (sendResult.getOffsetMsgId() != null) { + id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); + } else { + id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); + } + } catch (Exception e) { + log.warn("genFromBrokerTransactionId failed. brokerAddr: {}, sendResult: {}", brokerAddr, sendResult, e); + } + return genFromBrokerTransactionId(RemotingUtil.string2SocketAddress(brokerAddr), sendResult.getTransactionId(), + id.getOffset(), sendResult.getQueueOffset()); + } + + public static TransactionId genFromBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, + long commitLogOffset, long tranStateTableOffset) { + byte[] orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); + + ByteBuffer byteBuffer = ByteBuffer.allocate(8 + 4 + orgTransactionIdByte.length + 8 + 8); + byteBuffer.put(MessageExt.socketAddress2ByteBuffer(brokerAddr)); + + byteBuffer.putInt(orgTransactionIdByte.length); + byteBuffer.put(orgTransactionIdByte); + byteBuffer.putLong(commitLogOffset); + byteBuffer.putLong(tranStateTableOffset); + + String gatewayTransactionId = UtilAll.bytes2string(byteBuffer.array()); + + return TransactionId.builder() + .brokerAddr(brokerAddr) + .brokerTransactionId(orgTransactionId) + .commitLogOffset(commitLogOffset) + .tranStateTableOffset(tranStateTableOffset) + .gatewayTransactionId(gatewayTransactionId) + .build(); + } + + public static TransactionId genFromGatewayTransactionId(String gatewayTransactionId) throws UnknownHostException { + ByteBuffer byteBuffer = ByteBuffer.wrap(UtilAll.string2bytes(gatewayTransactionId)); + + byte[] ip = new byte[4]; + byteBuffer.get(ip); + int port = byteBuffer.getInt(); + SocketAddress brokerAddr = new InetSocketAddress(InetAddress.getByAddress(ip), port); + + int orgTransactionIdLen = byteBuffer.getInt(); + byte[] orgTransactionIdByte = new byte[orgTransactionIdLen]; + byteBuffer.get(orgTransactionIdByte); + + long commitLogOffset = byteBuffer.getLong(); + long tranStateTableOffset = byteBuffer.getLong(); + + return TransactionId.builder() + .brokerAddr(brokerAddr) + .brokerTransactionId(new String(orgTransactionIdByte, StandardCharsets.UTF_8)) + .commitLogOffset(commitLogOffset) + .tranStateTableOffset(tranStateTableOffset) + .gatewayTransactionId(gatewayTransactionId) + .build(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionId id = (TransactionId) o; + return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && Objects.equals(brokerAddr, id.brokerAddr) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && Objects.equals(gatewayTransactionId, id.gatewayTransactionId); + } + + @Override + public int hashCode() { + return Objects.hash(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, gatewayTransactionId); + } + + public static TransactionIdBuilder builder() { + return new TransactionIdBuilder(); + } + + public SocketAddress getBrokerAddr() { + return this.brokerAddr; + } + + public String getBrokerTransactionId() { + return this.brokerTransactionId; + } + + public long getCommitLogOffset() { + return this.commitLogOffset; + } + + public long getTranStateTableOffset() { + return this.tranStateTableOffset; + } + + public String getGatewayTransactionId() { + return this.gatewayTransactionId; + } + + public void setBrokerAddr(SocketAddress brokerAddr) { + this.brokerAddr = brokerAddr; + } + + public void setBrokerTransactionId(String brokerTransactionId) { + this.brokerTransactionId = brokerTransactionId; + } + + public void setCommitLogOffset(long commitLogOffset) { + this.commitLogOffset = commitLogOffset; + } + + public void setTranStateTableOffset(long tranStateTableOffset) { + this.tranStateTableOffset = tranStateTableOffset; + } + + public void setGatewayTransactionId(String gatewayTransactionId) { + this.gatewayTransactionId = gatewayTransactionId; + } + + public String toString() { + return "TransactionId(brokerAddr=" + this.getBrokerAddr() + ", brokerTransactionId=" + this.getBrokerTransactionId() + ", commitLogOffset=" + this.getCommitLogOffset() + ", tranStateTableOffset=" + this.getTranStateTableOffset() + ", gatewayTransactionId=" + this.getGatewayTransactionId() + ")"; + } + + public static class TransactionIdBuilder { + private SocketAddress brokerAddr; + private String brokerTransactionId; + private long commitLogOffset; + private long tranStateTableOffset; + private String gatewayTransactionId; + + TransactionIdBuilder() { + } + + public TransactionIdBuilder brokerAddr(SocketAddress brokerAddr) { + this.brokerAddr = brokerAddr; + return this; + } + + public TransactionIdBuilder brokerTransactionId(String brokerTransactionId) { + this.brokerTransactionId = brokerTransactionId; + return this; + } + + public TransactionIdBuilder commitLogOffset(long commitLogOffset) { + this.commitLogOffset = commitLogOffset; + return this; + } + + public TransactionIdBuilder tranStateTableOffset(long tranStateTableOffset) { + this.tranStateTableOffset = tranStateTableOffset; + return this; + } + + public TransactionIdBuilder gatewayTransactionId(String gatewayTransactionId) { + this.gatewayTransactionId = gatewayTransactionId; + return this; + } + + public TransactionId build() { + return new TransactionId(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, gatewayTransactionId); + } + + public String toString() { + return "TransactionId.TransactionIdBuilder(brokerAddr=" + this.brokerAddr + ", brokerTransactionId=" + this.brokerTransactionId + ", commitLogOffset=" + this.commitLogOffset + ", tranStateTableOffset=" + this.tranStateTableOffset + ", gatewayTransactionId=" + this.gatewayTransactionId + ")"; + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java new file mode 100644 index 0000000000..246ddde201 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java @@ -0,0 +1,86 @@ +/* + * 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.client.transaction; + +import org.apache.rocketmq.common.message.MessageExt; + +public class TransactionStateCheckRequest { + private String groupId; + private Long tranStateTableOffset; + private Long commitLogOffset; + private String msgId; + private TransactionId transactionId; + private MessageExt messageExt; + + public TransactionStateCheckRequest(String groupId, Long tranStateTableOffset, Long commitLogOffset, + String msgId, TransactionId transactionId, MessageExt messageExt) { + this.groupId = groupId; + this.tranStateTableOffset = tranStateTableOffset; + this.commitLogOffset = commitLogOffset; + this.msgId = msgId; + this.transactionId = transactionId; + this.messageExt = messageExt; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public Long getTranStateTableOffset() { + return tranStateTableOffset; + } + + public void setTranStateTableOffset(Long tranStateTableOffset) { + this.tranStateTableOffset = tranStateTableOffset; + } + + public Long getCommitLogOffset() { + return commitLogOffset; + } + + public void setCommitLogOffset(Long commitLogOffset) { + this.commitLogOffset = commitLogOffset; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public TransactionId getTransactionId() { + return transactionId; + } + + public void setTransactionId(TransactionId transactionId) { + this.transactionId = transactionId; + } + + public MessageExt getMessageExt() { + return messageExt; + } + + public void setMessageExt(MessageExt messageExt) { + this.messageExt = messageExt; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java new file mode 100644 index 0000000000..bfbb0e7c43 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.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.proxy.client.transaction; + +public interface TransactionStateChecker { + + void checkTransactionState(TransactionStateCheckRequest checkData); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java new file mode 100644 index 0000000000..250d3b3d61 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.common; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public abstract class AbstractStartAndShutdown implements StartAndShutdown { + + protected List startAndShutdownList = new CopyOnWriteArrayList<>(); + + public AbstractStartAndShutdown appendStartAndShutdown(StartAndShutdown startAndShutdown) { + this.startAndShutdownList.add(startAndShutdown); + return this; + } + + @Override + public void start() throws Exception { + for (StartAndShutdown startAndShutdown : startAndShutdownList) { + startAndShutdown.start(); + } + } + + @Override + public void shutdown() throws Exception { + int index = startAndShutdownList.size() - 1; + for (; index >= 0; index--) { + startAndShutdownList.get(index).shutdown(); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java new file mode 100644 index 0000000000..80d49ed8e3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.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.common; + +import com.google.common.cache.CacheLoader; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListenableFutureTask; +import java.util.concurrent.ThreadPoolExecutor; + +public abstract class RetainCacheLoader extends CacheLoader { + private final ThreadPoolExecutor cacheRefreshExecutor; + + public RetainCacheLoader(ThreadPoolExecutor cacheRefreshExecutor) { + this.cacheRefreshExecutor = cacheRefreshExecutor; + } + + @Override + public ListenableFuture reload(K key, V oldValue) throws Exception { + ListenableFutureTask task = ListenableFutureTask.create(() -> { + try { + return getDirectly(key); + } catch (Exception e) { + onErr(key, e); + return oldValue; + } + }); + cacheRefreshExecutor.execute(task); + return task; + } + + @Override + public V load(K key) throws Exception { + return getDirectly(key); + } + + protected abstract V getDirectly(K key) throws Exception; + + protected abstract void onErr(K key, Exception e); +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java new file mode 100644 index 0000000000..a1488cf017 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.common; + +import org.apache.rocketmq.client.common.ClientErrorCode; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.protocol.ResponseCode; + +public class RocketMQHelper { + + public static boolean isTopicNotExistError(Throwable e) { + if (e instanceof MQBrokerException) { + if (((MQBrokerException) e).getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { + return true; + } + } + if (e instanceof MQClientException) { + if (((MQClientException) e).getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { + return true; + } + + if (((MQClientException) e).getResponseCode() == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION) { + return true; + } + + Throwable cause = e.getCause(); + if (cause instanceof MQClientException) { + if (((MQClientException) cause).getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { + return true; + } + + return ((MQClientException) cause).getResponseCode() == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION; + } + } + return false; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java index aa0ea6809a..ffb2523e97 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/StartAndShutdown.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.common; public interface StartAndShutdown { void start() throws Exception; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java new file mode 100644 index 0000000000..5a9a711fb9 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -0,0 +1,24 @@ +/* + * 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.common.utils; + +import java.time.Duration; + +public class ProxyUtils { + + public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java index 58a8a2537a..e69d31ae4c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -34,6 +34,9 @@ public class ProxyConfig { private boolean enablePrintJstack = true; private long printJstackPeriodMillis = 60000; + private String nameSrvAddr = "11.165.223.199:9876"; + private String nameSrvDomain = ""; + private String nameSrvDomainSubgroup = ""; /** * gRPC */ @@ -53,6 +56,22 @@ public class ProxyConfig { */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; + private int expiredChannelTimeSec = 120; + + private int consumerClientNum = 2; + private double consumerClientWorkerFactor = 0.2f; + private int producerClientNum = 2; + private double producerClientWorkerFactor = 0.2f; + private int defaultClientNum = 2; + private double defaultClientWorkerFactor = 0.2f; + + private int topicRouteCacheExpireSecond = 20; + private int topicRouteCacheExecutorThreadNum = 3; + private int topicRouteCacheExecutorQueueCapacity = 1000; + private int topicRouteCacheMaxNum = 20000; + private int topicRouteThreadPoolNums = 36; + private int topicRouteThreadPoolQueueCapacity = 50000; + public Integer getHealthCheckPort() { return healthCheckPort; } @@ -85,6 +104,30 @@ public class ProxyConfig { this.printJstackPeriodMillis = printJstackPeriodMillis; } + public String getNameSrvAddr() { + return nameSrvAddr; + } + + public void setNameSrvAddr(String nameSrvAddr) { + this.nameSrvAddr = nameSrvAddr; + } + + public String getNameSrvDomain() { + return nameSrvDomain; + } + + public void setNameSrvDomain(String nameSrvDomain) { + this.nameSrvDomain = nameSrvDomain; + } + + public String getNameSrvDomainSubgroup() { + return nameSrvDomainSubgroup; + } + + public void setNameSrvDomainSubgroup(String nameSrvDomainSubgroup) { + this.nameSrvDomainSubgroup = nameSrvDomainSubgroup; + } + public String getProxyMode() { return proxyMode; } @@ -172,4 +215,108 @@ public class ProxyConfig { public void setGrpcMaxInboundMessageSize(int grpcMaxInboundMessageSize) { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } + + public int getExpiredChannelTimeSec() { + return expiredChannelTimeSec; + } + + public void setExpiredChannelTimeSec(int expiredChannelTimeSec) { + this.expiredChannelTimeSec = expiredChannelTimeSec; + } + + public int getConsumerClientNum() { + return consumerClientNum; + } + + public void setConsumerClientNum(int consumerClientNum) { + this.consumerClientNum = consumerClientNum; + } + + public double getConsumerClientWorkerFactor() { + return consumerClientWorkerFactor; + } + + public void setConsumerClientWorkerFactor(double consumerClientWorkerFactor) { + this.consumerClientWorkerFactor = consumerClientWorkerFactor; + } + + public int getProducerClientNum() { + return producerClientNum; + } + + public void setProducerClientNum(int producerClientNum) { + this.producerClientNum = producerClientNum; + } + + public double getProducerClientWorkerFactor() { + return producerClientWorkerFactor; + } + + public void setProducerClientWorkerFactor(double producerClientWorkerFactor) { + this.producerClientWorkerFactor = producerClientWorkerFactor; + } + + public int getDefaultClientNum() { + return defaultClientNum; + } + + public void setDefaultClientNum(int defaultClientNum) { + this.defaultClientNum = defaultClientNum; + } + + public double getDefaultClientWorkerFactor() { + return defaultClientWorkerFactor; + } + + public void setDefaultClientWorkerFactor(double defaultClientWorkerFactor) { + this.defaultClientWorkerFactor = defaultClientWorkerFactor; + } + + public int getTopicRouteCacheExpireSecond() { + return topicRouteCacheExpireSecond; + } + + public void setTopicRouteCacheExpireSecond(int topicRouteCacheExpireSecond) { + this.topicRouteCacheExpireSecond = topicRouteCacheExpireSecond; + } + + public int getTopicRouteCacheExecutorThreadNum() { + return topicRouteCacheExecutorThreadNum; + } + + public void setTopicRouteCacheExecutorThreadNum(int topicRouteCacheExecutorThreadNum) { + this.topicRouteCacheExecutorThreadNum = topicRouteCacheExecutorThreadNum; + } + + public int getTopicRouteCacheExecutorQueueCapacity() { + return topicRouteCacheExecutorQueueCapacity; + } + + public void setTopicRouteCacheExecutorQueueCapacity(int topicRouteCacheExecutorQueueCapacity) { + this.topicRouteCacheExecutorQueueCapacity = topicRouteCacheExecutorQueueCapacity; + } + + public int getTopicRouteCacheMaxNum() { + return topicRouteCacheMaxNum; + } + + public void setTopicRouteCacheMaxNum(int topicRouteCacheMaxNum) { + this.topicRouteCacheMaxNum = topicRouteCacheMaxNum; + } + + public int getTopicRouteThreadPoolNums() { + return topicRouteThreadPoolNums; + } + + public void setTopicRouteThreadPoolNums(int topicRouteThreadPoolNums) { + this.topicRouteThreadPoolNums = topicRouteThreadPoolNums; + } + + public int getTopicRouteThreadPoolQueueCapacity() { + return topicRouteThreadPoolQueueCapacity; + } + + public void setTopicRouteThreadPoolQueueCapacity(int topicRouteThreadPoolQueueCapacity) { + this.topicRouteThreadPoolQueueCapacity = topicRouteThreadPoolQueueCapacity; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java index 8a9aac74f4..4a791f3b3c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java @@ -53,7 +53,7 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import io.netty.util.concurrent.CompleteFuture; -import org.apache.rocketmq.proxy.grpc.common.StartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; public interface GrpcService extends StartAndShutdown { CompleteFuture queryRoute(Context ctx, QueryRouteRequest request); From 80b2f95d1786f0c8f4440a10ae74f5ad9d3c666b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 11 Mar 2022 16:43:41 +0800 Subject: [PATCH 009/338] [ISSUE #3949] Support sendMessage in Local mode --- .../rocketmq/common/message/MessageConst.java | 3 + .../proxy/grpc/adapter/InvocationContext.java | 48 ++++ .../grpc/adapter/channel/ChannelManager.java | 88 +++++++ .../adapter/channel/SendMessageChannel.java | 51 ++++ .../grpc/adapter/channel/SimpleChannel.java | 241 +++++++++++++++++ .../channel/SimpleChannelHandlerContext.java | 247 ++++++++++++++++++ .../grpc/adapter/handler/ResponseHandler.java | 25 ++ .../handler/SendMessageResponseHandler.java | 46 ++++ .../rocketmq/proxy/grpc/common/Converter.java | 131 ++++++++++ .../grpc/common/InterceptorConstants.java | 65 +++++ .../proxy/grpc/common/ResponseBuilder.java | 96 +++++++ .../proxy/grpc/common/ResponseWriter.java | 61 +++++ .../proxy/grpc/service/LocalGrpcService.java | 51 ++++ 13 files changed, 1153 insertions(+) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ResponseHandler.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java index a823466415..d82cc07012 100644 --- a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java +++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java @@ -65,6 +65,9 @@ public class MessageConst { public static final String PROPERTY_REDIRECT = "REDIRECT"; public static final String PROPERTY_INNER_MULTI_DISPATCH = "INNER_MULTI_DISPATCH"; public static final String PROPERTY_INNER_MULTI_QUEUE_OFFSET = "INNER_MULTI_QUEUE_OFFSET"; + public static final String PROPERTY_TRACE_CONTEXT = "TRACE_CONTEXT"; + public static final String PROPERTY_TIMER_DELAY_SEC = "TIMER_DELAY_SEC"; + public static final String PROPERTY_TIMER_DELIVER_MS = "TIMER_DELIVER_MS"; /** * property which name starts with "__RMQ.TRANSIENT." is called transient one that will not stored in broker disks. diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java new file mode 100644 index 0000000000..8b0739efd3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java @@ -0,0 +1,48 @@ +/* + * 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.grpc.adapter; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class InvocationContext { + final private R request; + final private CompletableFuture response; + final private long timestamp = System.currentTimeMillis(); + + public InvocationContext(R req, CompletableFuture resp) { + request = req; + response = resp; + } + + public boolean expired(long expiredTimeSec) { + return System.currentTimeMillis() - timestamp >= TimeUnit.SECONDS.toMillis(expiredTimeSec); + } + + public R getRequest() { + return request; + } + + public CompletableFuture getResponse() { + return response; + } + + public long getTimestamp() { + return timestamp; + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java new file mode 100644 index 0000000000..24dec4a302 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java @@ -0,0 +1,88 @@ +/* + * 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.grpc.adapter.channel; + +import com.google.common.base.Strings; +import io.grpc.Context; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ChannelManager { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final ConcurrentMap> clientIdChannelMap = new ConcurrentHashMap<>(); + + public SimpleChannel createChannel() { + final String clientId = anonymousChannelId(); + if (Strings.isNullOrEmpty(clientId)) { + LOGGER.warn("ClientId is unexpected null or empty"); + return createChannelInner(); + } + + if (!clientIdChannelMap.containsKey(clientId)) { + clientIdChannelMap.putIfAbsent(clientId, createChannelInner()); + } + + return clientIdChannelMap.get(clientId) + .updateLastAccessTime(); + } + + private String anonymousChannelId() { + final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.REMOTE_ADDRESS); + final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.LOCAL_ADDRESS); + return clientHost + "@" + localAddress; + } + + private SimpleChannel createChannelInner() { + final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.REMOTE_ADDRESS); + final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.LOCAL_ADDRESS); + return new SimpleChannel<>(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getExpiredChannelTimeSec()); + } + + /** + * Scan and remove inactive mocking channels; Scan and clean expired requests; + */ + public void scanAndCleanChannels() { + try { + Iterator>> iterator = clientIdChannelMap.entrySet() + .iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + if (!entry.getValue() + .isActive()) { + iterator.remove(); + } else { + entry.getValue() + .cleanExpiredRequests(); + } + } + } catch (Throwable e) { + LOGGER.error("Unexpected exception", e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java new file mode 100644 index 0000000000..646df00fc7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java @@ -0,0 +1,51 @@ +/* + * 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.grpc.adapter.channel; + +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.netty.channel.ChannelFuture; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class SendMessageChannel extends SimpleChannel { + private final SendMessageResponseHandler handler; + + public static SendMessageChannel create(SimpleChannel other, SendMessageResponseHandler handler) { + return new SendMessageChannel(other, handler); + } + + private SendMessageChannel(SimpleChannel other, SendMessageResponseHandler handler) { + super(other); + this.handler = handler; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + if (msg instanceof RemotingCommand) { + RemotingCommand responseCommand = (RemotingCommand) msg; + InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); + if (null != context) { + handler.handle(responseCommand, context); + } + } + + return super.writeAndFlush(msg); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java new file mode 100644 index 0000000000..eb170ffbc1 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java @@ -0,0 +1,241 @@ +/* + * 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.grpc.adapter.channel; + +import com.google.common.base.Strings; +import io.netty.channel.AbstractChannel; +import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelMetadata; +import io.netty.channel.ChannelOutboundBuffer; +import io.netty.channel.DefaultChannelPromise; +import io.netty.channel.EventLoop; +import io.netty.util.concurrent.GlobalEventExecutor; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * SimpleChannel is used to handle writeAndFlush situation in processor + * @see io.netty.channel.ChannelHandlerContext#writeAndFlush + * @see io.netty.channel.Channel#writeAndFlush + */ +public class SimpleChannel extends AbstractChannel { + + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + private final String remoteAddress; + private final String localAddress; + private final long expiredTimeSec; + + private long lastAccessTime; + + protected final ConcurrentMap> inFlightRequestMap; + + /** + * Creates a new instance. + * + * @param parent the parent of this channel. {@code null} if there's no parent. + * @param remoteAddress Remote address + * @param localAddress Local address + * @param expiredTimeSec Expired time second for cleaning channel + */ + public SimpleChannel(Channel parent, String remoteAddress, String localAddress, long expiredTimeSec) { + super(parent); + lastAccessTime = System.currentTimeMillis(); + this.remoteAddress = remoteAddress; + this.localAddress = localAddress; + this.inFlightRequestMap = new ConcurrentHashMap<>(); + this.expiredTimeSec = expiredTimeSec; + } + + public SimpleChannel(SimpleChannel other) { + super(other); + lastAccessTime = System.currentTimeMillis(); + this.remoteAddress = other.remoteAddress; + this.localAddress = other.localAddress; + this.inFlightRequestMap = other.inFlightRequestMap; + this.expiredTimeSec = other.expiredTimeSec; + } + + @Override + protected AbstractUnsafe newUnsafe() { + return null; + } + + @Override + protected boolean isCompatible(EventLoop loop) { + return false; + } + + private static SocketAddress parseSocketAddress(String address) { + if (Strings.isNullOrEmpty(address)) { + return null; + } + + String[] segments = address.split(":"); + if (2 == segments.length) { + return new InetSocketAddress(segments[0], Integer.parseInt(segments[1])); + } + + return null; + } + + @Override + protected SocketAddress localAddress0() { + return parseSocketAddress(localAddress); + } + + @Override + public SocketAddress localAddress() { + return localAddress0(); + } + + @Override + public SocketAddress remoteAddress() { + return remoteAddress0(); + } + + @Override + protected SocketAddress remoteAddress0() { + return parseSocketAddress(remoteAddress); + } + + @Override + protected void doBind(SocketAddress localAddress) throws Exception { + + } + + @Override + protected void doDisconnect() throws Exception { + + } + + @Override + public ChannelFuture close() { + DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); + promise.setSuccess(); + return promise; + } + + @Override + protected void doClose() throws Exception { + + } + + @Override + protected void doBeginRead() throws Exception { + + } + + @Override + protected void doWrite(ChannelOutboundBuffer in) throws Exception { + + } + + public boolean isWritable(int opaque) { + if (!inFlightRequestMap.containsKey(opaque)) { + return false; + } + + InvocationContext invocationContext = inFlightRequestMap.get(opaque); + if (null != invocationContext) { + CompletableFuture future = invocationContext.getResponse(); + return null != future && !future.isCancelled() && !future.isCompletedExceptionally() && !future.isDone(); + } + return false; + } + + @Override + public ChannelConfig config() { + return null; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public boolean isActive() { + return (System.currentTimeMillis() - lastAccessTime) <= 120L * 1000; + } + + @Override + public ChannelMetadata metadata() { + return null; + } + + @Override + public EventLoop eventLoop() { + return super.eventLoop(); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + if (msg instanceof RemotingCommand) { + RemotingCommand responseCommand = (RemotingCommand) msg; + inFlightRequestMap.remove(responseCommand.getOpaque()); + } + + DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); + promise.setSuccess(); + return promise; + } + + public void registerInvocationContext(int opaque, InvocationContext context) { + inFlightRequestMap.put(opaque, context); + } + + public void eraseInvocationContext(int opaque) { + inFlightRequestMap.remove(opaque); + } + + public void cleanExpiredRequests() { + Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); + int count = 0; + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + if (entry.getValue().expired(expiredTimeSec)) { + iterator.remove(); + count++; + LOGGER.debug("An expired request is found, created time-point: {}, Request: {}", + entry.getValue().getTimestamp(), entry.getValue().getRequest()); + } + } + if (count > 0) { + LOGGER.warn("[BUG] {} expired in-flight requests is cleaned.", count); + } + } + + public SimpleChannel updateLastAccessTime() { + lastAccessTime = System.currentTimeMillis(); + return this; + } +} + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java new file mode 100644 index 0000000000..62d0c2a543 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java @@ -0,0 +1,247 @@ +/* + * 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.grpc.adapter.channel; + +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelProgressivePromise; +import io.netty.channel.ChannelPromise; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.concurrent.EventExecutor; +import java.net.SocketAddress; +import org.apache.commons.lang3.NotImplementedException; + +public class SimpleChannelHandlerContext implements ChannelHandlerContext { + + private final Channel channel; + + public SimpleChannelHandlerContext(Channel channel) { + this.channel = channel; + } + + @Override + public Channel channel() { + return channel; + } + + @Override + public EventExecutor executor() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public String name() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandler handler() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public boolean isRemoved() { + return false; + } + + @Override + public ChannelHandlerContext fireChannelRegistered() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelUnregistered() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelActive() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelInactive() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireExceptionCaught(Throwable cause) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireUserEventTriggered(Object evt) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelRead(Object msg) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelReadComplete() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelWritabilityChanged() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture disconnect() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture close() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture deregister() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture disconnect(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture close(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture deregister(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext read() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture write(Object msg) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture write(Object msg, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext flush() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { + return channel.writeAndFlush(msg, promise); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + return channel.writeAndFlush(msg); + } + + @Override + public ChannelPipeline pipeline() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ByteBufAllocator alloc() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelPromise newPromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelProgressivePromise newProgressivePromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture newSucceededFuture() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture newFailedFuture(Throwable cause) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelPromise voidPromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public Attribute attr(AttributeKey key) { + throw new NotImplementedException("Not implemented"); + } + + + @Override + public boolean hasAttr(AttributeKey attributeKey) { + return false; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ResponseHandler.java new file mode 100644 index 0000000000..c7fbb5bf38 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ResponseHandler.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.handler; + +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public interface ResponseHandler { + void handle(RemotingCommand responseCommand, InvocationContext context); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java new file mode 100644 index 0000000000..9ff4bc33fe --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.handler; + +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class SendMessageResponseHandler implements ResponseHandler { + private final String messageId; + + public SendMessageResponseHandler(String messageId) { + this.messageId = messageId; + } + + @Override public void handle(RemotingCommand responseCommand, + InvocationContext context) { + // If responseCommand equals to null, then the response has been written to channel. + // org.apache.rocketmq.broker.processor.SendMessageProcessor#handlePutMessageResult + // org.apache.rocketmq.broker.processor.AbstractSendMessageProcessor#doResponse + if (null != responseCommand) { + SendMessageResponse response = ResponseBuilder.buildSendMessageResponse(responseCommand); + response = response.toBuilder() + .setMessageId(messageId) + .build(); + context.getResponse().complete(response); + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index bb1737353f..bcdabe1663 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -17,5 +17,136 @@ package org.apache.rocketmq.proxy.grpc.common; +import apache.rocketmq.v1.Encoding; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.MessageType; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SystemAttribute; +import com.google.common.collect.Maps; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import java.util.List; +import java.util.Map; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; + public class Converter { + public static String getResourceNameWithNamespace(Resource resource) { + return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); + } + + public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request) { + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + + Message message = request.getMessage(); + SystemAttribute systemAttribute = message.getSystemAttribute(); + + Map property = buildMessageProperty(message); + requestHeader.setProducerGroup(getResourceNameWithNamespace(systemAttribute.getProducerGroup())); + requestHeader.setTopic(getResourceNameWithNamespace(message.getTopic())); + requestHeader.setDefaultTopic(""); + requestHeader.setDefaultTopicQueueNums(0); + requestHeader.setQueueId(systemAttribute.getPartitionId()); + // sysFlag (body encoding & message type) + int sysFlag = 0; + Encoding bodyEncoding = systemAttribute.getBodyEncoding(); + if (bodyEncoding.equals(Encoding.GZIP)) { + sysFlag |= MessageSysFlag.COMPRESSED_FLAG; + } + // transaction + MessageType messageType = systemAttribute.getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; + } + requestHeader.setSysFlag(sysFlag); + requestHeader.setBornTimestamp(Timestamps.toMillis(systemAttribute.getBornTimestamp())); + requestHeader.setFlag(0); + requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); + requestHeader.setReconsumeTimes(systemAttribute.getDeliveryAttempt()); + + return requestHeader; + } + + public static Map buildMessageProperty(Message message) { + org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); + // set user properties + Map userProperties = message.getUserAttributeMap(); + for (String key : userProperties.keySet()) { + if (MessageConst.STRING_HASH_SET.contains(key)) { + throw new IllegalArgumentException("Property is used by system: " + key); + } + } + MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); + // set tag + String tag = message.getSystemAttribute().getTag(); + if (!"".equals(tag)) { + messageWithHeader.setTags(tag); + } + // set keys + List keysList = message.getSystemAttribute().getKeysList(); + if (keysList.size() > 0) { + messageWithHeader.setKeys(keysList); + } + // set message id + String messageId = message.getSystemAttribute().getMessageId(); + if ("".equals(messageId)) { + throw new IllegalArgumentException("message id is empty"); + } + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); + // set transaction property + MessageType messageType = message.getSystemAttribute().getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); + + Duration transactionResolveDelay = message.getSystemAttribute().getOrphanedTransactionRecoveryPeriod(); + + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_CHECK_TIMES, String.valueOf(15)); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, + String.valueOf(Durations.toSeconds(transactionResolveDelay))); + } + // set delay level or deliver timestamp + switch (message.getSystemAttribute().getTimedDeliveryCase()) { + case DELAY_LEVEL: + int delayLevel = message.getSystemAttribute().getDelayLevel(); + if (delayLevel > 0) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_DELAY_TIME_LEVEL, + String.valueOf(delayLevel)); + } + break; + case DELIVERY_TIMESTAMP: + Timestamp deliveryTimestamp = message.getSystemAttribute().getDeliveryTimestamp(); + String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); + break; + case TIMEDDELIVERY_NOT_SET: + break; + default: + throw new IllegalStateException("Unexpected value: " + message.getSystemAttribute().getTimedDeliveryCase()); + } + // set reconsume times + int reconsumeTimes = message.getSystemAttribute().getDeliveryAttempt(); + MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); + // set producer group + Resource producerGroup = message.getSystemAttribute().getProducerGroup(); + String producerGroupName = getResourceNameWithNamespace(producerGroup); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroupName); + // set message group + String messageGroup = message.getSystemAttribute().getMessageGroup(); + if (!messageGroup.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); + } + // set trace context + String traceContext = message.getSystemAttribute().getTraceContext(); + if (!traceContext.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); + } + return messageWithHeader.getProperties(); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java new file mode 100644 index 0000000000..cb175d2ef9 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.common; + +import io.grpc.Context; +import io.grpc.Metadata; + +public class InterceptorConstants { + private InterceptorConstants() { + } + + public static final Context.Key METADATA = Context.key("rpc-metadata"); + + /** + * Remote address key in attributes of call + */ + public static final Metadata.Key REMOTE_ADDRESS + = Metadata.Key.of("rpc-remote-address", Metadata.ASCII_STRING_MARSHALLER); + + /** + * Local address key in attributes of call + */ + public static final Metadata.Key LOCAL_ADDRESS + = Metadata.Key.of("rpc-local-address", Metadata.ASCII_STRING_MARSHALLER); + + + public static final Metadata.Key AUTHORIZATION + = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key NAMESPACE_ID + = Metadata.Key.of("x-mq-namespace", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key DATE_TIME + = Metadata.Key.of("x-mq-date-time", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key REQUEST_ID + = Metadata.Key.of("x-mq-request-id", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key LANGUAGE + = Metadata.Key.of("x-mq-language", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key CLIENT_VERSION + = Metadata.Key.of("x-mq-client-version", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key PROTOCOL_VERSION + = Metadata.Key.of("x-mq-protocol", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key RPC_NAME + = Metadata.Key.of("x-mq-rpc-name", Metadata.ASCII_STRING_MARSHALLER); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index 7265295efc..4a05227b80 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -18,10 +18,26 @@ package org.apache.rocketmq.proxy.grpc.common; import apache.rocketmq.v1.ResponseCommon; +import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import com.google.rpc.Status; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ResponseBuilder { + public static ResponseCommon buildCommon(int responseCode, String remark) { + Status status = Status.newBuilder() + .setCode(buildCode(responseCode).getNumber()) + .setMessage(buildMessage(responseCode, remark)) + .build(); + + return ResponseCommon.newBuilder() + .setStatus(status) + .build(); + } + public static ResponseCommon buildCommon(Code code, String message) { Status status = Status.newBuilder() .setCode(code.getNumber()) @@ -32,4 +48,84 @@ public class ResponseBuilder { .setStatus(status) .build(); } + + public static SendMessageResponse buildSendMessageResponse(RemotingCommand command) { + SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) command.readCustomHeader(); + return SendMessageResponse.newBuilder() + .setCommon(buildCommon(command.getCode(), command.getRemark())) + .setMessageId(StringUtils.defaultString(responseHeader.getMsgId())) + .setTransactionId(StringUtils.defaultString(responseHeader.getTransactionId())) + .build(); + } + + public static Code buildCode(int responseCode) { + Code code; + switch (responseCode) { + case ResponseCode.SUCCESS: + case ResponseCode.NO_MESSAGE: { + code = Code.OK; + break; + } + case ResponseCode.SYSTEM_ERROR: { + code = Code.INTERNAL; + break; + } + case ResponseCode.SYSTEM_BUSY: + case ResponseCode.POLLING_FULL: { + code = Code.RESOURCE_EXHAUSTED; + break; + } + case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { + code = Code.UNIMPLEMENTED; + break; + } + case ResponseCode.MESSAGE_ILLEGAL: + case ResponseCode.VERSION_NOT_SUPPORTED: + case ResponseCode.SUBSCRIPTION_PARSE_FAILED: + case ResponseCode.FILTER_DATA_NOT_EXIST: { + code = Code.INVALID_ARGUMENT; + break; + } + case ResponseCode.SERVICE_NOT_AVAILABLE: + case ResponseCode.SLAVE_NOT_AVAILABLE: + case ResponseCode.PULL_RETRY_IMMEDIATELY: + case ResponseCode.PULL_OFFSET_MOVED: + case ResponseCode.SUBSCRIPTION_NOT_LATEST: + case ResponseCode.FILTER_DATA_NOT_LATEST: { + code = Code.UNAVAILABLE; + break; + } + case ResponseCode.NO_PERMISSION: { + code = Code.PERMISSION_DENIED; + break; + } + case ResponseCode.TOPIC_NOT_EXIST: + case ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST: + case ResponseCode.SUBSCRIPTION_NOT_EXIST: + case ResponseCode.PULL_NOT_FOUND: + case ResponseCode.QUERY_NOT_FOUND: + case ResponseCode.CONSUMER_NOT_ONLINE: { + code = Code.NOT_FOUND; + break; + } + case ResponseCode.POLLING_TIMEOUT: + case ResponseCode.FLUSH_DISK_TIMEOUT: + case ResponseCode.FLUSH_SLAVE_TIMEOUT: { + code = Code.DEADLINE_EXCEEDED; + break; + } + default: { + code = Code.UNKNOWN; + } + + } + return code; + } + + public static String buildMessage(int responseCode, String remark) { + if (remark != null) { + return "ResponseCode: " + responseCode + " " + remark; + } + return "ResponseCode: " + responseCode; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java new file mode 100644 index 0000000000..d8744813a8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.common; + +import io.grpc.stub.ServerCallStreamObserver; +import io.grpc.stub.StreamObserver; +import org.apache.rocketmq.common.constant.LoggerName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResponseWriter { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + public static void write(StreamObserver observer, final T response) { + if (observer instanceof ServerCallStreamObserver) { + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; + if (serverCallStreamObserver.isCancelled()) { + LOGGER.warn("client has cancelled the request. response to write: {}", response); + return; + } + + LOGGER.debug("start to write response. response: {}", response); + serverCallStreamObserver.onNext(response); + serverCallStreamObserver.onCompleted(); + } + } + + public static void writeException(StreamObserver observer, final Exception e) { + if (observer instanceof ServerCallStreamObserver) { + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; + if (null == e) { + return; + } + + if (serverCallStreamObserver.isCancelled()) { + LOGGER.warn("Client has cancelled the request. Exception to write", e); + return; + } + + LOGGER.debug("Start to write error response", e); + serverCallStreamObserver.onError(e); + serverCallStreamObserver.onCompleted(); + } + } +} + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index f4f03ade44..c415fa8daf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -29,6 +29,7 @@ import apache.rocketmq.v1.HealthCheckRequest; import apache.rocketmq.v1.HealthCheckResponse; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.Message; import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.NackMessageResponse; import apache.rocketmq.v1.NotifyClientTerminationRequest; @@ -53,17 +54,36 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import io.netty.util.concurrent.CompleteFuture; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +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.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.channel.ChannelManager; +import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.grpc.adapter.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LocalGrpcService implements GrpcService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final BrokerController brokerController; + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); + private final ChannelManager sendChannelManager; public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; + this.sendChannelManager = new ChannelManager<>(); } @Override public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -79,6 +99,31 @@ public class LocalGrpcService implements GrpcService { } @Override public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); + Message message = request.getMessage(); + command.setBody(message.getBody().toByteArray()); + command.makeCustomHeaderToNet(); + + SendMessageResponseHandler handler = new SendMessageResponseHandler(message.getSystemAttribute().getMessageId()); + SendMessageChannel channel = SendMessageChannel.create(sendChannelManager.createChannel(), handler); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + CompletableFuture future = new CompletableFuture<>(); + InvocationContext context + = new InvocationContext<>(request, future); + channel.registerInvocationContext(command.getOpaque(), context); + try { + CompletableFuture processorFuture = brokerController.getSendMessageProcessor() + .asyncProcessRequest(channelHandlerContext, command); + processorFuture.thenAccept(r -> { + handler.handle(r, context); + channel.eraseInvocationContext(command.getOpaque()); + }); + } catch (final RemotingCommandException e) { + LOGGER.error("Failed to process send message command", e); + channel.eraseInvocationContext(command.getOpaque()); + future.completeExceptionally(e); + } return null; } @@ -143,9 +188,15 @@ public class LocalGrpcService implements GrpcService { @Override public void start() throws Exception { this.brokerController.start(); + this.scheduledExecutorService.scheduleWithFixedDelay(this::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); } @Override public void shutdown() throws Exception { + this.scheduledExecutorService.shutdown(); this.brokerController.shutdown(); } + + private void scanAndCleanChannels() { + this.sendChannelManager.scanAndCleanChannels(); + } } From 4059688c76f3daa21e9ff968ba2d7e1e88c4bf06 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 14 Mar 2022 14:23:19 +0800 Subject: [PATCH 010/338] [ISSUE #3949] Add HeaderInterceptor --- .../rocketmq/proxy/grpc/GrpcServer.java | 2 + .../grpc/interceptor/HeaderInterceptor.java | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java 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 3a522a47f9..a23b540f54 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 @@ -31,6 +31,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.service.GrpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,6 +92,7 @@ public class GrpcServer { .channelType(NioServerSocketChannel.class) .addService(messagingProcessor) .executor(this.executor) + .intercept(new HeaderInterceptor()) .build(); log.info( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java new file mode 100644 index 0000000000..d09ccdadb5 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.interceptor; + +import com.google.common.net.HostAndPort; +import io.grpc.Grpc; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; + +public class HeaderInterceptor implements ServerInterceptor { + @Override + public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, + ServerCallHandler next) { + SocketAddress remoteSocketAddress = call.getAttributes() + .get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR); + String remoteAddress = parseSocketAddress(remoteSocketAddress); + headers.put(InterceptorConstants.REMOTE_ADDRESS, remoteAddress); + + SocketAddress localSocketAddress = call.getAttributes() + .get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR); + String localAddress = parseSocketAddress(localSocketAddress); + headers.put(InterceptorConstants.LOCAL_ADDRESS, localAddress); + return next.startCall(call, headers); + } + + + private String parseSocketAddress(SocketAddress socketAddress) { + if (socketAddress instanceof InetSocketAddress) { + InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + return HostAndPort.fromParts(inetSocketAddress.getAddress() + .getHostAddress(), inetSocketAddress.getPort()) + .toString(); + } + + return ""; + } +} From 38ab97cc3105eafd89e17d29b2208465ec87aa0a Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 14 Mar 2022 14:49:20 +0800 Subject: [PATCH 011/338] [ISSUE #3949] Use CompletableFuture --- .../grpc/service/ClusterGrpcService.java | 36 +++++++++---------- .../proxy/grpc/service/GrpcService.java | 36 +++++++++---------- .../proxy/grpc/service/LocalGrpcService.java | 35 +++++++++--------- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index f67e0d6ec8..3703ff5039 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -52,7 +52,7 @@ import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; -import io.netty.util.concurrent.CompleteFuture; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,80 +65,80 @@ public class ClusterGrpcService implements GrpcService { } @Override - public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { return null; } @Override - public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { return null; } @Override - public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { + public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { return null; } @Override - public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { return null; } @Override - public CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { return null; } - @Override public CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { return null; } - @Override public CompleteFuture ackMessage(Context ctx, AckMessageRequest request) { + @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { return null; } - @Override public CompleteFuture nackMessage(Context ctx, NackMessageRequest request) { + @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { return null; } @Override - public CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { return null; } - @Override public CompleteFuture endTransaction(Context ctx, EndTransactionRequest request) { + @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { return null; } - @Override public CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request) { + @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { return null; } - @Override public CompleteFuture pullMessage(Context ctx, PullMessageRequest request) { + @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { return null; } - @Override public CompleteFuture pollCommand(Context ctx, PollCommandRequest request) { + @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { return null; } - @Override public CompleteFuture reportThreadStackTrace(Context ctx, + @Override public CompletableFuture reportThreadStackTrace(Context ctx, ReportThreadStackTraceRequest request) { return null; } - @Override public CompleteFuture reportMessageConsumptionResult(Context ctx, + @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { return null; } - @Override public CompleteFuture notifyClientTermination(Context ctx, + @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { return null; } - @Override public CompleteFuture changeInvisibleDuration(Context ctx, + @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java index 4a791f3b3c..bd51796922 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java @@ -52,46 +52,46 @@ import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; -import io.netty.util.concurrent.CompleteFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import java.util.concurrent.CompletableFuture; public interface GrpcService extends StartAndShutdown { - CompleteFuture queryRoute(Context ctx, QueryRouteRequest request); + CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); - CompleteFuture heartbeat(Context ctx, HeartbeatRequest request); + CompletableFuture heartbeat(Context ctx, HeartbeatRequest request); - CompleteFuture healthCheck(Context ctx, HealthCheckRequest request); + CompletableFuture healthCheck(Context ctx, HealthCheckRequest request); - CompleteFuture sendMessage(Context ctx, SendMessageRequest request); + CompletableFuture sendMessage(Context ctx, SendMessageRequest request); - CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request); + CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request); + CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request); - CompleteFuture ackMessage(Context ctx, AckMessageRequest request); + CompletableFuture ackMessage(Context ctx, AckMessageRequest request); - CompleteFuture nackMessage(Context ctx, NackMessageRequest request); + CompletableFuture nackMessage(Context ctx, NackMessageRequest request); - CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); - CompleteFuture endTransaction(Context ctx, EndTransactionRequest request); + CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); - CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request); + CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request); - CompleteFuture pullMessage(Context ctx, PullMessageRequest request); + CompletableFuture pullMessage(Context ctx, PullMessageRequest request); - CompleteFuture pollCommand(Context ctx, PollCommandRequest request); + CompletableFuture pollCommand(Context ctx, PollCommandRequest request); - CompleteFuture reportThreadStackTrace(Context ctx, + CompletableFuture reportThreadStackTrace(Context ctx, ReportThreadStackTraceRequest request); - CompleteFuture reportMessageConsumptionResult(Context ctx, + CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request); - CompleteFuture notifyClientTermination(Context ctx, + CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); - CompleteFuture changeInvisibleDuration(Context ctx, + CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index c415fa8daf..3433075cec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -53,7 +53,6 @@ import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; -import io.netty.util.concurrent.CompleteFuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -86,19 +85,19 @@ public class LocalGrpcService implements GrpcService { this.sendChannelManager = new ChannelManager<>(); } - @Override public CompleteFuture queryRoute(Context ctx, QueryRouteRequest request) { + @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { return null; } - @Override public CompleteFuture heartbeat(Context ctx, HeartbeatRequest request) { + @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { return null; } - @Override public CompleteFuture healthCheck(Context ctx, HealthCheckRequest request) { + @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { return null; } - @Override public CompleteFuture sendMessage(Context ctx, SendMessageRequest request) { + @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); Message message = request.getMessage(); @@ -128,60 +127,60 @@ public class LocalGrpcService implements GrpcService { } @Override - public CompleteFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { return null; } - @Override public CompleteFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { return null; } - @Override public CompleteFuture ackMessage(Context ctx, AckMessageRequest request) { + @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { return null; } - @Override public CompleteFuture nackMessage(Context ctx, NackMessageRequest request) { + @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { return null; } @Override - public CompleteFuture forwardMessageToDeadLetterQueue(Context ctx, + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { return null; } - @Override public CompleteFuture endTransaction(Context ctx, EndTransactionRequest request) { + @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { return null; } - @Override public CompleteFuture queryOffset(Context ctx, QueryOffsetRequest request) { + @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { return null; } - @Override public CompleteFuture pullMessage(Context ctx, PullMessageRequest request) { + @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { return null; } - @Override public CompleteFuture pollCommand(Context ctx, PollCommandRequest request) { + @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { return null; } - @Override public CompleteFuture reportThreadStackTrace(Context ctx, + @Override public CompletableFuture reportThreadStackTrace(Context ctx, ReportThreadStackTraceRequest request) { return null; } - @Override public CompleteFuture reportMessageConsumptionResult(Context ctx, + @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { return null; } - @Override public CompleteFuture notifyClientTermination(Context ctx, + @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { return null; } - @Override public CompleteFuture changeInvisibleDuration(Context ctx, + @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { return null; } From 6fcefe10e77b77c4363542b8944d0b7e59fbc319 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 14 Mar 2022 14:49:52 +0800 Subject: [PATCH 012/338] [ISSUE #3949] Add sendMessage in GrpcMessagingProcessor --- .../proxy/grpc/GrpcMessagingProcessor.java | 16 ++++++++++++++++ .../proxy/grpc/common/ResponseWriter.java | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index 297a32f29c..040c11aa9a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -18,6 +18,12 @@ package org.apache.rocketmq.proxy.grpc; import apache.rocketmq.v1.MessagingServiceGrpc; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.grpc.common.ResponseWriter; import org.apache.rocketmq.proxy.grpc.service.GrpcService; public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { @@ -26,4 +32,14 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic public GrpcMessagingProcessor(GrpcService grpcService) { this.grpcService = grpcService; } + + @Override + public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcService.sendMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java index d8744813a8..d524cc055e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java @@ -40,7 +40,7 @@ public class ResponseWriter { } } - public static void writeException(StreamObserver observer, final Exception e) { + public static void writeException(StreamObserver observer, final Throwable e) { if (observer instanceof ServerCallStreamObserver) { final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (null == e) { From b7c9e97f2ba85cea8125d8da90485a20e7480293 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 14 Mar 2022 17:03:57 +0800 Subject: [PATCH 013/338] [ISSUE #3949] Add UT for LocalGrpcService --- pom.xml | 2 +- .../configuration/ConfigurationManager.java | 2 +- .../proxy/grpc/common/ResponseBuilder.java | 10 +- .../proxy/grpc/service/LocalGrpcService.java | 5 +- .../grpc/service/LocalGrpcServiceTest.java | 141 ++++++++++++++++++ 5 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java diff --git a/pom.xml b/pom.xml index 09a1af5226..851600fd10 100644 --- a/pom.xml +++ b/pom.xml @@ -586,7 +586,7 @@ com.google.guava guava - 19.0 + 30.1-jre com.googlecode.concurrentlinkedhashmap diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java index 79617e9686..b940f5cc87 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ConfigurationManager.java @@ -21,7 +21,7 @@ import java.io.File; import org.apache.commons.lang3.StringUtils; public class ConfigurationManager { - protected static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; + public static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; protected static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; private static String proxyHome; private static Configuration configuration; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index 4a05227b80..d8f87c6b89 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -51,10 +51,16 @@ public class ResponseBuilder { public static SendMessageResponse buildSendMessageResponse(RemotingCommand command) { SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) command.readCustomHeader(); + String messageId = ""; + String transactionId = ""; + if (responseHeader != null) { + messageId = responseHeader.getMsgId(); + transactionId = responseHeader.getTransactionId(); + } return SendMessageResponse.newBuilder() .setCommon(buildCommon(command.getCode(), command.getRemark())) - .setMessageId(StringUtils.defaultString(responseHeader.getMsgId())) - .setTransactionId(StringUtils.defaultString(responseHeader.getTransactionId())) + .setMessageId(StringUtils.defaultString(messageId)) + .setTransactionId(StringUtils.defaultString(transactionId)) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 3433075cec..77c30738ff 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -68,7 +68,6 @@ import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -118,12 +117,12 @@ public class LocalGrpcService implements GrpcService { handler.handle(r, context); channel.eraseInvocationContext(command.getOpaque()); }); - } catch (final RemotingCommandException e) { + } catch (final Exception e) { LOGGER.error("Failed to process send message command", e); channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } - return null; + return future; } @Override diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java new file mode 100644 index 0000000000..4f0bf9a7a6 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -0,0 +1,141 @@ +/* + * 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.grpc.service; + +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.SystemAttribute; +import com.google.rpc.Code; +import io.grpc.Context; +import io.grpc.Metadata; +import io.netty.channel.ChannelHandlerContext; +import java.net.URL; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(MockitoJUnitRunner.class) +public class LocalGrpcServiceTest { + private LocalGrpcService localGrpcService; + @Mock + SendMessageProcessor sendMessageProcessorMock; + + @Before + public void setUp() throws Exception { + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + BrokerController brokerControllerMock = Mockito.mock(BrokerController.class); + Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + localGrpcService = new LocalGrpcService(brokerControllerMock); + } + + @Test + public void testSendMessageError() throws RemotingCommandException { + String remark = "store putMessage return null"; + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SYSTEM_ERROR, remark); + CompletableFuture future = CompletableFuture.completedFuture(response); + Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(future); + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("123") + .build()) + .build()) + .build(); + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); + + CompletableFuture grpcFuture = localGrpcService.sendMessage( + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + grpcFuture.thenAccept(r -> { + assertThat(r.getCommon().getStatus().getCode()) + .isEqualTo(Code.INTERNAL.getNumber()); + assertThat(r.getCommon().getStatus().getMessage()) + .isEqualTo(remark); + }); + } + + @Test + public void testSendMessageWriteAndFlush() throws RemotingCommandException { + CompletableFuture future = CompletableFuture.completedFuture(null); + Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(future); + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("123") + .build()) + .build()) + .build(); + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); + + CompletableFuture grpcFuture = localGrpcService.sendMessage( + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + grpcFuture.thenAccept(r -> assertThat(r).isNull()); + } + + @Test + public void testSendMessageWithException() throws RemotingCommandException { + Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenThrow(new RemotingCommandException("test")); + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("123") + .build()) + .build()) + .build(); + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); + + CompletableFuture grpcFuture = localGrpcService.sendMessage( + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + grpcFuture.thenAccept(r -> assertThat(r).isNull()).exceptionally(e -> { + assertThat(e).isInstanceOf(RemotingCommandException.class); + return null; + }); + } +} \ No newline at end of file From e319024fa2b3e619e32672ae129c4a4dde7699c4 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Mon, 14 Mar 2022 17:26:01 +0800 Subject: [PATCH 014/338] [ISSUE #3949] Add logger config and rename GrpcService to GrpcForwardService. --- .../rocketmq/common/constant/LoggerName.java | 1 + distribution/conf/logback_proxy.xml | 420 ++++++++++++++++++ .../apache/rocketmq/proxy/ProxyStartup.java | 4 +- .../proxy/common/utils/ProxyUtils.java | 1 - .../proxy/grpc/GrpcMessagingProcessor.java | 10 +- .../rocketmq/proxy/grpc/GrpcServer.java | 27 +- .../grpc/adapter/channel/ChannelManager.java | 1 + .../grpc/service/ClusterGrpcService.java | 2 +- ...pcService.java => GrpcForwardService.java} | 2 +- .../proxy/grpc/service/LocalGrpcService.java | 9 +- 10 files changed, 450 insertions(+), 27 deletions(-) create mode 100644 distribution/conf/logback_proxy.xml rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/{GrpcService.java => GrpcForwardService.java} (98%) 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 151cbf460c..3d764b56dd 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 @@ -44,5 +44,6 @@ public class LoggerName { public static final String ROCKETMQ_POP_LOGGER_NAME = "RocketmqPop"; public static final String FAILOVER_LOGGER_NAME = "RocketmqFailover"; public static final String STDOUT_LOGGER_NAME = "STDOUT"; + public static final String PROXY_LOGGER_NAME = "RocketmqProxy"; public static final String GRPC_LOGGER_NAME = "RocketmqGrpc"; } diff --git a/distribution/conf/logback_proxy.xml b/distribution/conf/logback_proxy.xml new file mode 100644 index 0000000000..8d0458ebf0 --- /dev/null +++ b/distribution/conf/logback_proxy.xml @@ -0,0 +1,420 @@ + + + + + + + ${user.home}/logs/rocketmqlogs/proxy.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/proxy.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/grpc.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/grpc.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker_default.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker_default.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/protection.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/protection.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/watermark.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/watermark.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/store.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/store.%i.log.gz + 1 + 10 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/remoting.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/remoting.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/storeerror.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/storeerror.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/transaction.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/transaction.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/lock.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/lock.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/filter.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/filter.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/stats.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/stats.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/commercial.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/commercial.%i.log.gz + 1 + 10 + + + 500MB + + + + + ${user.home}/logs/rocketmqlogs/pop.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/pop.%i.log + + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + true + + %d{yyy-MM-dd HH\:mm\:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 b89627fa19..e70a227cbd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -31,7 +31,7 @@ import org.apache.rocketmq.proxy.configuration.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.service.GrpcService; +import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,7 +85,7 @@ public class ProxyStartup { } private static GrpcServer createGrpcServer() throws RuntimeException { - GrpcService grpcService; + GrpcForwardService grpcService; String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); if (ProxyMode.isClusterMode(proxyModeStr)) { grpcService = new ClusterGrpcService(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index 5a9a711fb9..f335cdfa0a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -19,6 +19,5 @@ package org.apache.rocketmq.proxy.common.utils; import java.time.Duration; public class ProxyUtils { - public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index 040c11aa9a..dfa2006fe4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -24,18 +24,18 @@ import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.grpc.common.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.service.GrpcService; +import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { - private final GrpcService grpcService; + private final GrpcForwardService grpcForwardService; - public GrpcMessagingProcessor(GrpcService grpcService) { - this.grpcService = grpcService; + public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { + this.grpcForwardService = grpcForwardService; } @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcService.sendMessage(Context.current(), request); + CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.writeException(responseObserver, e); 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 a23b540f54..8ebec3d4b7 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,24 +29,23 @@ import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; -import org.apache.rocketmq.proxy.grpc.service.GrpcService; +import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GrpcServer { - - private static final Logger log = LoggerFactory.getLogger(GrpcServer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final io.grpc.Server server; - private final ThreadPoolExecutor executor; - private final GrpcService grpcService; + private final GrpcForwardService grpcForwardService; - public GrpcServer(GrpcService grpcService) { - this.grpcService = grpcService; + public GrpcServer(GrpcForwardService grpcForwardService) { + this.grpcForwardService = grpcForwardService; int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(port); @@ -63,7 +62,7 @@ public class GrpcServer { .build(); serverBuilder.sslContext(sslContext); } catch (IOException e) { - log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); + LOGGER.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); throw new RuntimeException("grpc tls set failed: " + e.getMessage()); } @@ -78,7 +77,7 @@ public class GrpcServer { threadPoolQueueCapacity ); - GrpcMessagingProcessor messagingProcessor = new GrpcMessagingProcessor(grpcService); + GrpcMessagingProcessor messagingProcessor = new GrpcMessagingProcessor(grpcForwardService); // build server int bossLoopNum = ConfigurationManager.getProxyConfig().getGrpcBossLoopNum(); @@ -95,7 +94,7 @@ public class GrpcServer { .intercept(new HeaderInterceptor()) .build(); - log.info( + LOGGER.info( "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", port, tlsKeyPath, tlsCertPath, threadPoolNums, threadPoolQueueCapacity, @@ -105,10 +104,10 @@ public class GrpcServer { public void start() throws Exception { // first to start grpc service. - this.grpcService.start(); + this.grpcForwardService.start(); this.server.start(); - log.info("grpc server has started"); + LOGGER.info("grpc server has started"); } public void shutdown() { @@ -116,9 +115,9 @@ public class GrpcServer { this.server.shutdown().awaitTermination(30, TimeUnit.SECONDS); this.executor.shutdown(); - this.grpcService.shutdown(); + this.grpcForwardService.shutdown(); - log.info("grpc server has stopped"); + LOGGER.info("grpc server has stopped"); } catch (Exception e) { e.printStackTrace(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java index 24dec4a302..66f8d86275 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java @@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory; public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final ConcurrentMap> clientIdChannelMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 3703ff5039..ce739b6792 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -57,7 +57,7 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ClusterGrpcService implements GrpcService { +public class ClusterGrpcService implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); public ClusterGrpcService() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java index bd51796922..a8efceb2f1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java @@ -55,7 +55,7 @@ import io.grpc.Context; import org.apache.rocketmq.proxy.common.StartAndShutdown; import java.util.concurrent.CompletableFuture; -public interface GrpcService extends StartAndShutdown { +public interface GrpcForwardService extends StartAndShutdown { CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); CompletableFuture heartbeat(Context ctx, HeartbeatRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 77c30738ff..329fe71c62 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -72,8 +72,9 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalGrpcService implements GrpcService { +public class LocalGrpcService implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final BrokerController brokerController; private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); @@ -96,7 +97,8 @@ public class LocalGrpcService implements GrpcService { return null; } - @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + @Override + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); Message message = request.getMessage(); @@ -130,7 +132,8 @@ public class LocalGrpcService implements GrpcService { return null; } - @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + @Override + public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { return null; } From 23c14ff738f281f4d0f8bf3eb2038e44772fe327 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 11:36:29 +0800 Subject: [PATCH 015/338] [ISSUE #3949] Add Base Initialization for test cases. --- .../client/impl/MQClientAPIExtImpl.java | 2 +- .../proxy/client/TopicRouteCache.java | 4 +- .../mqconstructor/MQClientAPIConstructor.java | 5 +- .../ConfigurationManagerTest.java | 23 +- .../configuration/InitConfigurationTest.java | 63 +++ .../grpc/service/LocalGrpcServiceTest.java | 17 +- .../rmq-proxy-home/conf/logback_proxy.xml | 420 ++++++++++++++++++ 7 files changed, 494 insertions(+), 40 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigurationTest.java create mode 100644 proxy/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java index d3713c58cb..ce3c548424 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -78,7 +78,7 @@ public class MQClientAPIExtImpl { ex = new MQClientException("wait response timeout " + responseFuture.getTimeoutMillis() + "ms", responseFuture.getCause()); } else { - ex = new MQClientException("unknow reseaon", responseFuture.getCause()); + ex = new MQClientException("unknown reason", responseFuture.getCause()); } return ex; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index 1e346266cd..287841dc1b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -73,7 +73,7 @@ public class TopicRouteCache { return res; } - protected static boolean routeDataIsValid(TopicRouteData routeData) { + protected static boolean isTopicRouteValid(TopicRouteData routeData) { return routeData != null && routeData.getQueueDatas() != null && !routeData.getQueueDatas().isEmpty() && routeData.getBrokerDatas() != null && !routeData.getBrokerDatas().isEmpty(); } @@ -97,7 +97,7 @@ public class TopicRouteCache { try { TopicRouteData topicRouteData = loadTopicRouteData(topic); - if (routeDataIsValid(topicRouteData)) { + if (isTopicRouteValid(topicRouteData)) { MessageQueueWrapper tmp = new MessageQueueWrapper(topic, topicRouteData); log.info("load {} from namesrv. topic: {}, queue: {}", loaderName(), topic, tmp); return tmp; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java index b9a3773060..f3e276c7a7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java @@ -29,11 +29,14 @@ public class MQClientAPIConstructor extends AbstractRocketMQClientConstructor + + + + + + ${user.home}/logs/rocketmqlogs/proxy.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/proxy.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/grpc.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/grpc.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker_default.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker_default.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/protection.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/protection.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/watermark.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/watermark.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/store.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/store.%i.log.gz + 1 + 10 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/remoting.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/remoting.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/storeerror.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/storeerror.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/transaction.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/transaction.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/lock.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/lock.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/filter.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/filter.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/stats.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/stats.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/commercial.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/commercial.%i.log.gz + 1 + 10 + + + 500MB + + + + + ${user.home}/logs/rocketmqlogs/pop.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/pop.%i.log + + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + true + + %d{yyy-MM-dd HH\:mm\:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 64f22d91030d9e12e74e0c2d9f642f57d07c2281 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 11:43:16 +0800 Subject: [PATCH 016/338] [ISSUE #3949] Add UT for clientManager. --- .../proxy/client/ClientManagerTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java new file mode 100644 index 0000000000..9a5703aa36 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java @@ -0,0 +1,51 @@ +/* + * 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.client; + +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ClientManagerTest extends InitConfigurationTest { + + @Test + public void testClientManager() throws Exception { + TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); + ClientManager clientManager = new ClientManager(mockedTransactionStateChecker); + clientManager.start(); + + assertThat(clientManager.getDefaultClient()).isNotNull(); + assertThat(clientManager.getDefaultClient().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultClientNum()); + + assertThat(clientManager.getProducerClient()).isNotNull(); + assertThat(clientManager.getProducerClient().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getProducerClientNum()); + + assertThat(clientManager.getReadConsumerClient()).isNotNull(); + assertThat(clientManager.getReadConsumerClient().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getConsumerClientNum()); + + + + } +} From 8d924e9e690a2f2376928d82b5265f3e482fdd3a Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 15:25:07 +0800 Subject: [PATCH 017/338] [ISSUE #3949] refactor SelectableMessageQueue. --- .../proxy/client/TopicRouteCache.java | 6 +- .../client/route/MessageQueueWrapper.java | 6 +- .../client/route/SelectableMessageQueue.java | 137 +++++++++--------- 3 files changed, 72 insertions(+), 77 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index 287841dc1b..e013cc4e4e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -66,7 +66,7 @@ public class TopicRouteCache { protected static MessageQueueWrapper getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { MessageQueueWrapper res = topicCache.get(key); - if (res.isEmptyCacheQueue()) { + if (res.isEmptyCachedQueue()) { throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "No topic route info in name server for the topic: " + key); } @@ -102,10 +102,10 @@ public class TopicRouteCache { log.info("load {} from namesrv. topic: {}, queue: {}", loaderName(), topic, tmp); return tmp; } - return MessageQueueWrapper.EMPTY_CACHE_QUEUES; + return MessageQueueWrapper.EMPTY_CACHED_QUEUE; } catch (Exception e) { if (RocketMQHelper.isTopicNotExistError(e)) { - return MessageQueueWrapper.EMPTY_CACHE_QUEUES; + return MessageQueueWrapper.EMPTY_CACHED_QUEUE; } throw e; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java index bfffbe31cc..5198d7bbfe 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.client.route; import org.apache.rocketmq.common.protocol.route.TopicRouteData; public class MessageQueueWrapper { - public static final MessageQueueWrapper EMPTY_CACHE_QUEUES = new MessageQueueWrapper("", new TopicRouteData()); + public static final MessageQueueWrapper EMPTY_CACHED_QUEUE = new MessageQueueWrapper("", new TopicRouteData()); private final SelectableMessageQueue read; private final SelectableMessageQueue write; @@ -40,8 +40,8 @@ public class MessageQueueWrapper { return topicRouteWrapper.getTopicName(); } - public boolean isEmptyCacheQueue() { - return this == EMPTY_CACHE_QUEUES; + public boolean isEmptyCachedQueue() { + return this == EMPTY_CACHED_QUEUE; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java index 1ed80ff522..390b19a577 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java @@ -18,50 +18,50 @@ package org.apache.rocketmq.proxy.client.route; 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.Objects; import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.route.QueueData; public class SelectableMessageQueue { + private static final int BROKER_ACTING_QUEUE_ID = -1; - // queueId : normal - private final List queues; - // queueId : -1 - private final List brokers; - private final Map brokerNameMap; + // multiple queues for one broker, with queueId : normal + private final List queues = new ArrayList<>(); + // one queue for one broker, with queueId : -1 + private final List brokerActingQueues = new ArrayList<>(); + private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); private final AtomicInteger queueIndex; private final AtomicInteger brokerIndex; public SelectableMessageQueue(TopicRouteWrapper topicRouteWrapper, boolean read) { - this.queues = new ArrayList<>(); - this.brokers = new ArrayList<>(); - this.brokerNameMap = new HashMap<>(); if (read) { this.queues.addAll(buildRead(topicRouteWrapper)); } else { this.queues.addAll(buildWrite(topicRouteWrapper)); } - buildBroker(topicRouteWrapper.getTopicName(), this.queues); + buildBrokerActingQueues(topicRouteWrapper.getTopicName(), this.queues); this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); this.brokerIndex = new AtomicInteger(Math.abs(new Random().nextInt())); } - private static List buildRead( - TopicRouteWrapper topicRoute) { - List queues = new ArrayList<>(); + private static List buildRead(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); List qds = topicRoute.getQueueDatas(); if (qds == null) { - return queues; + return new ArrayList<>(); } - Collections.sort(qds); + for (QueueData qd : qds) { if (PermName.isReadable(qd.getPerm())) { String brokerAddr = topicRoute.getMasterAddrPrefer(qd.getBrokerName()); @@ -73,20 +73,16 @@ public class SelectableMessageQueue { AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), brokerAddr); - if (!queues.contains(mq)) { - queues.add(mq); - } + queueSet.add(mq); } } } - Collections.sort(queues); - return queues; + return queueSet.stream().sorted().collect(Collectors.toList()); } - private static List buildWrite( - TopicRouteWrapper topicRoute) { - List queues = new ArrayList<>(); + private static List buildWrite(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); // order topic route. if (StringUtils.isNotBlank(topicRoute.getOrderTopicConf())) { String[] brokers = topicRoute.getOrderTopicConf().split(";"); @@ -103,61 +99,59 @@ public class SelectableMessageQueue { AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), brokerName, i), brokerAddr); - if (!queues.contains(mq)) { - queues.add(mq); - } + queueSet.add(mq); } } } else { List qds = topicRoute.getQueueDatas(); if (qds == null) { - return queues; + return new ArrayList<>(); } - Collections.sort(qds); + for (QueueData qd : qds) { if (PermName.isWriteable(qd.getPerm())) { - String brokerName = qd.getBrokerName(); - String brokerAddr = topicRoute.getMasterAddr(brokerName); + String brokerAddr = topicRoute.getMasterAddr(qd.getBrokerName()); if (brokerAddr == null) { continue; } for (int i = 0; i < qd.getWriteQueueNums(); i++) { AddressableMessageQueue mq = new AddressableMessageQueue( - new MessageQueue(topicRoute.getTopicName(), brokerName, i), + new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), brokerAddr); - if (!queues.contains(mq)) { - queues.add(mq); - } + queueSet.add(mq); } } } } - Collections.sort(queues); - return queues; + return queueSet.stream().sorted().collect(Collectors.toList()); } - private void buildBroker(String topic, List queues) { - for (AddressableMessageQueue messageQueue : queues) { - AddressableMessageQueue mb = new AddressableMessageQueue( - new MessageQueue(topic, messageQueue.getMessageQueue().getBrokerName(), -1), - messageQueue.getBrokerAddr()); - if (!brokers.contains(mb)) { - brokers.add(mb); - brokerNameMap.put(mb.getBrokerName(), mb); + + // 这里应该不是线程安全的 + private void buildBrokerActingQueues(String topic, List normalQueues) { + for (AddressableMessageQueue mq : normalQueues) { + AddressableMessageQueue brokerActingQueue = new AddressableMessageQueue( + new MessageQueue(topic, mq.getMessageQueue().getBrokerName(), BROKER_ACTING_QUEUE_ID), + mq.getBrokerAddr()); + + if (!brokerActingQueues.contains(brokerActingQueue)) { + brokerActingQueues.add(brokerActingQueue); + brokerNameQueueMap.put(brokerActingQueue.getBrokerName(), brokerActingQueue); } } - Collections.sort(brokers); + Collections.sort(brokerActingQueues); } - public final AddressableMessageQueue getBrokerByName(String brokerName) { - return this.brokerNameMap.get(brokerName); + public final AddressableMessageQueue getQueueByBrokerName(String brokerName) { + return this.brokerNameQueueMap.get(brokerName); } public final AddressableMessageQueue selectOne(boolean onlyBroker) { - return selectOneByIndex(onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(), onlyBroker); + int nextIndex = onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(); + return selectOneByIndex(nextIndex, onlyBroker); } public final AddressableMessageQueue selectOne(String brokerName, int queueId) { @@ -172,22 +166,23 @@ public class SelectableMessageQueue { public final AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { if (onlyBroker) { - if (brokers.isEmpty()) { + if (brokerActingQueues.isEmpty()) { return null; } - return brokers.get(Math.abs(index) % brokers.size()); + return brokerActingQueues.get(Math.abs(index) % brokerActingQueues.size()); } + if (queues.isEmpty()) { return null; } return queues.get(Math.abs(index) % queues.size()); } - public final AddressableMessageQueue selectNextOne( - AddressableMessageQueue last) { + // find next same type(but different) queue with last(normal queue or broker acting queue). + public final AddressableMessageQueue selectNextQueue(AddressableMessageQueue last) { boolean onlyBroker = last.getQueueId() < 0; AddressableMessageQueue newOne = last; - int count = onlyBroker ? brokers.size() : queues.size(); + int count = onlyBroker ? brokerActingQueues.size() : queues.size(); for (int i = 0; i < count; i++) { newOne = selectOne(onlyBroker); @@ -199,21 +194,21 @@ public class SelectableMessageQueue { return newOne; } - public final AddressableMessageQueue selectNextBrokerOne( - AddressableMessageQueue last) { - boolean onlyBroker = last.getQueueId() < 0; - AddressableMessageQueue newOne = last; - int count = onlyBroker ? brokers.size() : queues.size(); - - for (int i = 0; i < count; i++) { - newOne = selectOne(onlyBroker); - if (!newOne.getBrokerName().equals(last.getBrokerName())) { - break; - } - } - - return newOne; - } + // should use selectNextQueue +// public final AddressableMessageQueue selectNextBrokerActingQueue(AddressableMessageQueue last) { +// boolean onlyBroker = last.getQueueId() < 0; +// AddressableMessageQueue newOne = last; +// int count = onlyBroker ? brokerActingQueues.size() : queues.size(); +// +// for (int i = 0; i < count; i++) { +// newOne = selectOne(onlyBroker); +// if (!newOne.getBrokerName().equals(last.getBrokerName())) { +// break; +// } +// } +// +// return newOne; +// } @Override public boolean equals(Object o) { @@ -225,18 +220,18 @@ public class SelectableMessageQueue { } SelectableMessageQueue queue = (SelectableMessageQueue) o; return Objects.equals(queues, queue.queues) && - Objects.equals(brokers, queue.brokers); + Objects.equals(brokerActingQueues, queue.brokerActingQueues); } @Override public int hashCode() { - return Objects.hash(queues, brokers); + return Objects.hash(queues, brokerActingQueues); } @Override public String toString() { return "SelectableMessageQueue{" + "queues=" + queues + - ", brokers=" + brokers + + ", brokers=" + brokerActingQueues + ", queueIndex=" + queueIndex + ", brokerIndex=" + brokerIndex + '}'; From 115030a80f9d2a2d7e9472ec534fea7293dab21e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 14 Mar 2022 20:16:09 +0800 Subject: [PATCH 018/338] [ISSUE #3949] Refector SimpleChannel --- .../adapter => }/channel/ChannelManager.java | 29 ++++--- .../proxy/channel/InvocationChannel.java | 83 +++++++++++++++++++ .../adapter => }/channel/SimpleChannel.java | 75 +++-------------- .../channel/SimpleChannelHandlerContext.java | 2 +- .../proxy/grpc/GrpcMessagingProcessor.java | 16 ++++ .../adapter/channel/SendMessageChannel.java | 10 ++- .../proxy/grpc/service/LocalGrpcService.java | 17 ++-- 7 files changed, 144 insertions(+), 88 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => }/channel/ChannelManager.java (73%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => }/channel/SimpleChannel.java (63%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => }/channel/SimpleChannelHandlerContext.java (99%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java similarity index 73% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 66f8d86275..2c9ff07d9a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.channel; import com.google.common.base.Strings; import io.grpc.Context; @@ -25,16 +25,16 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ChannelManager { +public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); - private final ConcurrentMap> clientIdChannelMap = new ConcurrentHashMap<>(); - - public SimpleChannel createChannel() { + public SimpleChannel createChannel() { final String clientId = anonymousChannelId(); if (Strings.isNullOrEmpty(clientId)) { LOGGER.warn("ClientId is unexpected null or empty"); @@ -45,8 +45,9 @@ public class ChannelManager { clientIdChannelMap.putIfAbsent(clientId, createChannelInner()); } - return clientIdChannelMap.get(clientId) - .updateLastAccessTime(); + SimpleChannel channel = clientIdChannelMap.get(clientId); + channel.updateLastAccessTime(); + return channel; } private String anonymousChannelId() { @@ -57,12 +58,12 @@ public class ChannelManager { return clientHost + "@" + localAddress; } - private SimpleChannel createChannelInner() { + private SimpleChannel createChannelInner() { final String clientHost = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.REMOTE_ADDRESS); final String localAddress = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.LOCAL_ADDRESS); - return new SimpleChannel<>(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getExpiredChannelTimeSec()); + return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getExpiredChannelTimeSec()); } /** @@ -70,16 +71,18 @@ public class ChannelManager { */ public void scanAndCleanChannels() { try { - Iterator>> iterator = clientIdChannelMap.entrySet() + Iterator> iterator = clientIdChannelMap.entrySet() .iterator(); while (iterator.hasNext()) { - Map.Entry> entry = iterator.next(); + Map.Entry entry = iterator.next(); if (!entry.getValue() .isActive()) { iterator.remove(); } else { - entry.getValue() - .cleanExpiredRequests(); + if (entry.getValue() instanceof SendMessageChannel) { + SendMessageChannel channel = (SendMessageChannel) entry.getValue(); + channel.cleanExpiredRequests(); + } } } } catch (Throwable e) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java new file mode 100644 index 0000000000..4c70cc74c8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -0,0 +1,83 @@ +/* + * 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.channel; + +import io.netty.channel.ChannelFuture; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class InvocationChannel extends SimpleChannel { + protected final ConcurrentMap> inFlightRequestMap; + + public InvocationChannel(SimpleChannel simpleChannel) { + super(simpleChannel); + this.inFlightRequestMap = new ConcurrentHashMap<>(); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + if (msg instanceof RemotingCommand) { + RemotingCommand responseCommand = (RemotingCommand) msg; + inFlightRequestMap.remove(responseCommand.getOpaque()); + } + return super.writeAndFlush(msg); + } + + public boolean isWritable(int opaque) { + if (!inFlightRequestMap.containsKey(opaque)) { + return false; + } + + InvocationContext invocationContext = inFlightRequestMap.get(opaque); + if (null != invocationContext) { + CompletableFuture future = invocationContext.getResponse(); + return null != future && !future.isCancelled() && !future.isCompletedExceptionally() && !future.isDone(); + } + return false; + } + + public void registerInvocationContext(int opaque, InvocationContext context) { + inFlightRequestMap.put(opaque, context); + } + + public void eraseInvocationContext(int opaque) { + inFlightRequestMap.remove(opaque); + } + + public void cleanExpiredRequests() { + Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); + int count = 0; + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + if (entry.getValue().expired(expiredTimeSec)) { + iterator.remove(); + count++; + LOGGER.debug("An expired request is found, created time-point: {}, Request: {}", + entry.getValue().getTimestamp(), entry.getValue().getRequest()); + } + } + if (count > 0) { + LOGGER.warn("[BUG] {} expired in-flight requests is cleaned.", count); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java similarity index 63% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java index eb170ffbc1..a7305e1c92 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.channel; import com.google.common.base.Strings; import io.netty.channel.AbstractChannel; @@ -29,14 +29,7 @@ import io.netty.channel.EventLoop; import io.netty.util.concurrent.GlobalEventExecutor; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,17 +38,15 @@ import org.slf4j.LoggerFactory; * @see io.netty.channel.ChannelHandlerContext#writeAndFlush * @see io.netty.channel.Channel#writeAndFlush */ -public class SimpleChannel extends AbstractChannel { +public class SimpleChannel extends AbstractChannel { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + protected static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final String remoteAddress; - private final String localAddress; - private final long expiredTimeSec; + protected final String remoteAddress; + protected final String localAddress; + protected final long expiredTimeSec; - private long lastAccessTime; - - protected final ConcurrentMap> inFlightRequestMap; + protected long lastAccessTime; /** * Creates a new instance. @@ -70,16 +61,14 @@ public class SimpleChannel extends AbstractChannel { lastAccessTime = System.currentTimeMillis(); this.remoteAddress = remoteAddress; this.localAddress = localAddress; - this.inFlightRequestMap = new ConcurrentHashMap<>(); this.expiredTimeSec = expiredTimeSec; } - public SimpleChannel(SimpleChannel other) { + public SimpleChannel(SimpleChannel other) { super(other); - lastAccessTime = System.currentTimeMillis(); + lastAccessTime = other.lastAccessTime; this.remoteAddress = other.remoteAddress; this.localAddress = other.localAddress; - this.inFlightRequestMap = other.inFlightRequestMap; this.expiredTimeSec = other.expiredTimeSec; } @@ -158,19 +147,6 @@ public class SimpleChannel extends AbstractChannel { } - public boolean isWritable(int opaque) { - if (!inFlightRequestMap.containsKey(opaque)) { - return false; - } - - InvocationContext invocationContext = inFlightRequestMap.get(opaque); - if (null != invocationContext) { - CompletableFuture future = invocationContext.getResponse(); - return null != future && !future.isCancelled() && !future.isCompletedExceptionally() && !future.isDone(); - } - return false; - } - @Override public ChannelConfig config() { return null; @@ -198,44 +174,13 @@ public class SimpleChannel extends AbstractChannel { @Override public ChannelFuture writeAndFlush(Object msg) { - if (msg instanceof RemotingCommand) { - RemotingCommand responseCommand = (RemotingCommand) msg; - inFlightRequestMap.remove(responseCommand.getOpaque()); - } - DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); promise.setSuccess(); return promise; } - public void registerInvocationContext(int opaque, InvocationContext context) { - inFlightRequestMap.put(opaque, context); - } - - public void eraseInvocationContext(int opaque) { - inFlightRequestMap.remove(opaque); - } - - public void cleanExpiredRequests() { - Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); - int count = 0; - while (iterator.hasNext()) { - Map.Entry> entry = iterator.next(); - if (entry.getValue().expired(expiredTimeSec)) { - iterator.remove(); - count++; - LOGGER.debug("An expired request is found, created time-point: {}, Request: {}", - entry.getValue().getTimestamp(), entry.getValue().getRequest()); - } - } - if (count > 0) { - LOGGER.warn("[BUG] {} expired in-flight requests is cleaned.", count); - } - } - - public SimpleChannel updateLastAccessTime() { + public void updateLastAccessTime() { lastAccessTime = System.currentTimeMillis(); - return this; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java index 62d0c2a543..a78c5727f7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SimpleChannelHandlerContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.channel; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index dfa2006fe4..69edec9c96 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -17,22 +17,38 @@ package org.apache.rocketmq.proxy.grpc; +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HealthCheckResponse; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.MessagingServiceGrpc; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.grpc.common.ResponseWriter; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final GrpcForwardService grpcForwardService; public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { this.grpcForwardService = grpcForwardService; } + public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { + + } + + @Override + public void healthCheck(HealthCheckRequest request, StreamObserver responseObserver) { + } + @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java index 646df00fc7..08894d6fd3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java @@ -20,18 +20,20 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.netty.channel.ChannelFuture; +import org.apache.rocketmq.proxy.channel.InvocationChannel; +import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class SendMessageChannel extends SimpleChannel { +public class SendMessageChannel extends InvocationChannel { private final SendMessageResponseHandler handler; - public static SendMessageChannel create(SimpleChannel other, SendMessageResponseHandler handler) { - return new SendMessageChannel(other, handler); + public static SendMessageChannel create(SimpleChannel simpleChannel, SendMessageResponseHandler handler) { + return new SendMessageChannel(simpleChannel, handler); } - private SendMessageChannel(SimpleChannel other, SendMessageResponseHandler handler) { + private SendMessageChannel(SimpleChannel other, SendMessageResponseHandler handler) { super(other); this.handler = handler; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 329fe71c62..a2e140d91d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -52,6 +52,7 @@ import apache.rocketmq.v1.ReportThreadStackTraceRequest; import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; +import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -63,11 +64,12 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; -import org.apache.rocketmq.proxy.grpc.adapter.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,11 +80,11 @@ public class LocalGrpcService implements GrpcForwardService { private final BrokerController brokerController; private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); - private final ChannelManager sendChannelManager; + private final ChannelManager sendChannelManager; public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; - this.sendChannelManager = new ChannelManager<>(); + this.sendChannelManager = new ChannelManager(); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -90,11 +92,16 @@ public class LocalGrpcService implements GrpcForwardService { } @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + return null; } @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { - return null; + LOGGER.trace("Received health check request from client: {}", request.getClientHost()); + final HealthCheckResponse response = HealthCheckResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) + .build(); + return CompletableFuture.completedFuture(response); } @Override From 9e2dc9329cdba18555ec3afd8c9e06e6784ad6eb Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 11:47:42 +0800 Subject: [PATCH 019/338] [ISSUE #3949] Add code in GrpcMessagingProcessor --- .../proxy/grpc/GrpcMessagingProcessor.java | 182 +++++++++++++++++- .../proxy/grpc/common/ResponseWriter.java | 4 + 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index 69edec9c96..f1f026b4f0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -17,11 +17,39 @@ package org.apache.rocketmq.proxy.grpc; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.HealthCheckRequest; import apache.rocketmq.v1.HealthCheckResponse; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.MessagingServiceGrpc; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; +import apache.rocketmq.v1.ReportThreadStackTraceRequest; +import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; @@ -41,12 +69,34 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic this.grpcForwardService = grpcForwardService; } - public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { + @Override + public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryRoute(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + @Override + public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.heartbeat(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); } @Override public void healthCheck(HealthCheckRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.healthCheck(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); } @Override @@ -58,4 +108,134 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic return null; }); } + + @Override + public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryAssignment(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.receiveMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void nackMessage(NackMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.nackMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.endTransaction(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void queryOffset(QueryOffsetRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryOffset(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void pullMessage(PullMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.pullMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void pollCommand(PollCommandRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.pollCommand(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void reportThreadStackTrace(ReportThreadStackTraceRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.reportThreadStackTrace(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void reportMessageConsumptionResult(ReportMessageConsumptionResultRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.reportMessageConsumptionResult(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } + + @Override + public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.writeException(responseObserver, e); + return null; + }); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java index d524cc055e..5d8fff2998 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java @@ -28,6 +28,10 @@ public class ResponseWriter { public static void write(StreamObserver observer, final T response) { if (observer instanceof ServerCallStreamObserver) { + if (response == null) { + return; + } + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (serverCallStreamObserver.isCancelled()) { LOGGER.warn("client has cancelled the request. response to write: {}", response); From f5df79939721be4b437e04342e2cd57677beb509 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 11:56:11 +0800 Subject: [PATCH 020/338] [ISSUE #3949] Add heartbeat in LocalGrpcService --- .../grpc/adapter/channel/ChannelType.java | 29 +++++ .../rocketmq/proxy/grpc/common/Converter.java | 113 ++++++++++++++++++ .../proxy/grpc/common/ResponseBuilder.java | 7 ++ .../proxy/grpc/service/LocalGrpcService.java | 34 ++++-- .../grpc/service/LocalGrpcServiceTest.java | 46 ++++++- 5 files changed, 216 insertions(+), 13 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java new file mode 100644 index 0000000000..5a883b6a35 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.channel; + +public enum ChannelType { + /** + * The channel connect to current proxy directly + */ + LOCAL, + /** + * The channel sync from other proxy + */ + REMOTE +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index bcdabe1663..9ff4673763 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -17,27 +17,50 @@ package org.apache.rocketmq.proxy.grpc.common; +import apache.rocketmq.v1.ConsumeMessageType; +import apache.rocketmq.v1.ConsumeModel; +import apache.rocketmq.v1.ConsumePolicy; +import apache.rocketmq.v1.ConsumerData; import apache.rocketmq.v1.Encoding; +import apache.rocketmq.v1.FilterExpression; +import apache.rocketmq.v1.FilterType; +import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessageType; +import apache.rocketmq.v1.ProducerData; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SubscriptionEntry; import apache.rocketmq.v1.SystemAttribute; import com.google.common.collect.Maps; import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.filter.ExpressionType; +import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Converter { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + public static String getResourceNameWithNamespace(Resource resource) { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); } @@ -149,4 +172,94 @@ public class Converter { } return messageWithHeader.getProperties(); } + + public static String buildExpressionType(FilterType filterType) { + switch (filterType) { + case SQL: + return ExpressionType.SQL92; + case TAG: + default: + return ExpressionType.TAG; + } + } + + public static HeartbeatData buildHeartbeatData(HeartbeatRequest request) { + HeartbeatData heartbeatData = new HeartbeatData(); + heartbeatData.setClientID(request.getClientId()); + Set producerDataSet = new HashSet<>(); + producerDataSet.add(buildProducerData(request.getProducerData())); + heartbeatData.setProducerDataSet(producerDataSet); + Set consumerDataSet = new HashSet<>(); + consumerDataSet.add(buildConsumerData(request.getConsumerData())); + heartbeatData.setConsumerDataSet(consumerDataSet); + return heartbeatData; + } + + public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(ProducerData producerData) { + org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); + buildProducerData.setGroupName(getResourceNameWithNamespace(producerData.getGroup())); + return buildProducerData; + } + + public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(ConsumerData consumerData) { + org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); + buildConsumerData.setGroupName(getResourceNameWithNamespace(consumerData.getGroup())); + buildConsumerData.setConsumeType(buildConsumeType(consumerData.getConsumeType())); + buildConsumerData.setMessageModel(buildMessageModel(consumerData.getConsumeModel())); + buildConsumerData.setConsumeFromWhere(buildConsumeFromWhere(consumerData.getConsumePolicy())); + Set subscriptionDataSet = buildSubscriptionDataSet(consumerData.getSubscriptionsList()); + buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); + return buildConsumerData; + } + + public static ConsumeType buildConsumeType(ConsumeMessageType consumeMessageType) { + switch (consumeMessageType) { + case ACTIVE: + return ConsumeType.CONSUME_ACTIVELY; + case PASSIVE: + default: + return ConsumeType.CONSUME_PASSIVELY; + } + } + + public static MessageModel buildMessageModel(ConsumeModel consumeModel) { + switch (consumeModel) { + case BROADCASTING: + return MessageModel.BROADCASTING; + case CLUSTERING: + default: + return MessageModel.CLUSTERING; + } + } + + public static ConsumeFromWhere buildConsumeFromWhere(ConsumePolicy policy) { + switch (policy) { + case PLAYBACK: + return ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET; + case DISCARD: + return ConsumeFromWhere.CONSUME_FROM_MAX_OFFSET; + case TARGET_TIMESTAMP: + return ConsumeFromWhere.CONSUME_FROM_TIMESTAMP; + case RESUME: + default: + return ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET; + } + } + + public static Set buildSubscriptionDataSet(List subscriptionEntryList) { + Set subscriptionDataSet = new HashSet<>(); + for (SubscriptionEntry sub : subscriptionEntryList) { + String topicName = Converter.getResourceNameWithNamespace(sub.getTopic()); + FilterExpression filterExpression = sub.getExpression(); + String expression = filterExpression.getExpression(); + String expressionType = Converter.buildExpressionType(filterExpression.getType()); + try { + SubscriptionData subscriptionData = FilterAPI.build(topicName, expression, expressionType); + subscriptionDataSet.add(subscriptionData); + } catch (Exception e) { + throw new IllegalArgumentException("Build subscription failed when apply heartbeat", e); + } + } + return subscriptionDataSet; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index d8f87c6b89..25eddefd7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc.common; +import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.ResponseCommon; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; @@ -49,6 +50,12 @@ public class ResponseBuilder { .build(); } + public static HeartbeatResponse buildHeartbeatResponse(RemotingCommand command) { + return HeartbeatResponse.newBuilder() + .setCommon(buildCommon(command.getCode(), command.getRemark())) + .build(); + } + public static SendMessageResponse buildSendMessageResponse(RemotingCommand command) { SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) command.readCustomHeader(); String messageId = ""; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index a2e140d91d..4277c95a0e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -59,17 +59,22 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -80,11 +85,11 @@ public class LocalGrpcService implements GrpcForwardService { private final BrokerController brokerController; private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); - private final ChannelManager sendChannelManager; + private final ChannelManager channelManager; public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; - this.sendChannelManager = new ChannelManager(); + this.channelManager = new ChannelManager(); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -92,8 +97,23 @@ public class LocalGrpcService implements GrpcForwardService { } @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + LanguageCode languageCode; + String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); + languageCode = LanguageCode.valueOf(language); + HeartbeatData heartbeatData = Converter.buildHeartbeatData(request); - return null; + SimpleChannel channel = channelManager.createChannel(); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); + command.setLanguage(languageCode); + command.setVersion(MQVersion.Version.V5_0_0.ordinal()); + command.setBody(heartbeatData.encode()); + command.makeCustomHeaderToNet(); + + RemotingCommand response = this.brokerController.getClientManageProcessor() + .heartBeat(simpleChannelHandlerContext, command); + HeartbeatResponse heartbeatResponse = ResponseBuilder.buildHeartbeatResponse(response); + return CompletableFuture.completedFuture(heartbeatResponse); } @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { @@ -113,7 +133,7 @@ public class LocalGrpcService implements GrpcForwardService { command.makeCustomHeaderToNet(); SendMessageResponseHandler handler = new SendMessageResponseHandler(message.getSystemAttribute().getMessageId()); - SendMessageChannel channel = SendMessageChannel.create(sendChannelManager.createChannel(), handler); + SendMessageChannel channel = SendMessageChannel.create(channelManager.createChannel(), handler); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); InvocationContext context @@ -205,6 +225,6 @@ public class LocalGrpcService implements GrpcForwardService { } private void scanAndCleanChannels() { - this.sendChannelManager.scanAndCleanChannels(); + this.channelManager.scanAndCleanChannels(); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 781274c0a0..a16bf2cc42 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -17,6 +17,8 @@ package org.apache.rocketmq.proxy.grpc.service; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; @@ -27,6 +29,7 @@ import io.grpc.Metadata; import io.netty.channel.ChannelHandlerContext; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.ClientManageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; @@ -46,14 +49,48 @@ import static org.assertj.core.api.Assertions.assertThat; public class LocalGrpcServiceTest extends InitConfigurationTest { private LocalGrpcService localGrpcService; @Mock - SendMessageProcessor sendMessageProcessorMock; + private SendMessageProcessor sendMessageProcessorMock; + @Mock + private BrokerController brokerControllerMock; + + private Metadata metadata; @Before public void setUp() throws Exception { - super.before(); - BrokerController brokerControllerMock = Mockito.mock(BrokerController.class); + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); localGrpcService = new LocalGrpcService(brokerControllerMock); + metadata = new Metadata(); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); + metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + } + + @Test + public void testHeartbeat() { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); + Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); + HeartbeatRequest request = HeartbeatRequest.newBuilder().getDefaultInstanceForType(); + CompletableFuture grpcFuture = localGrpcService.heartbeat( + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + grpcFuture.thenAccept(r -> { + assertThat(r.getCommon().getStatus().getCode()) + .isEqualTo(Code.OK.getNumber()); + assertThat(r.getCommon().getStatus().getMessage()) + .isEqualTo(null); + }); } @Test @@ -70,9 +107,6 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { .build()) .build()) .build(); - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); From 85d4a368c8a52a5bed259601ba4d78a4b269d2aa Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 14:39:37 +0800 Subject: [PATCH 021/338] [ISSUE #3949] Add Converter.buildPopMessageRequestHeader --- .../rocketmq/proxy/grpc/common/Converter.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 9ff4673763..c04181da96 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -27,7 +27,9 @@ import apache.rocketmq.v1.FilterType; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessageType; +import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.ProducerData; +import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SubscriptionEntry; @@ -41,6 +43,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.filter.ExpressionType; @@ -49,6 +52,7 @@ import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; @@ -97,6 +101,39 @@ public class Converter { return requestHeader; } + public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { + Resource group = request.getGroup(); + String groupName = Converter.getResourceNameWithNamespace(group); + Partition partition = request.getPartition(); + Resource topic = partition.getTopic(); + String topicName = Converter.getResourceNameWithNamespace(topic); + int queueId = partition.getId(); + int maxMessageNumbers = request.getBatchSize(); + long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); + long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); + ConsumePolicy policy = request.getConsumePolicy(); + int initMode = Converter.buildConsumeInitMode(policy); + + FilterExpression filterExpression = request.getFilterExpression(); + String expression = filterExpression.getExpression(); + String expressionType = Converter.buildExpressionType(filterExpression.getType()); + + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setConsumerGroup(groupName); + requestHeader.setTopic(topicName); + requestHeader.setQueueId(queueId); + requestHeader.setMaxMsgNums(maxMessageNumbers); + requestHeader.setInvisibleTime(invisibleTime); + requestHeader.setPollTime(pollTime); + requestHeader.setBornTime(bornTime); + requestHeader.setInitMode(initMode); + requestHeader.setExpType(expressionType); + requestHeader.setExp(expression); + requestHeader.setOrder(request.getFifoFlag()); + + return requestHeader; + } + public static Map buildMessageProperty(Message message) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties @@ -262,4 +299,14 @@ public class Converter { } return subscriptionDataSet; } + + public static int buildConsumeInitMode(ConsumePolicy policy) { + switch (policy) { + case PLAYBACK: + return ConsumeInitMode.MIN; + case RESUME: + default: + return ConsumeInitMode.MAX; + } + } } From 0e5dee8b4f6e9fea039e01470a48bb63d0b1901a Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 15 Mar 2022 14:45:56 +0800 Subject: [PATCH 022/338] [ISSUE #3949] queryRoute, queryAssignment, sendMessage for cluster mode --- .../rocketmq/proxy/client/ClientManager.java | 10 +- .../proxy/client/TopicRouteCache.java | 20 ++ .../client/route/MessageQueueWrapper.java | 8 + .../client/route/SelectableMessageQueue.java | 8 + .../proxy/client/route/TopicRouteWrapper.java | 6 +- .../common/AbstractStartAndShutdown.java | 3 +- .../rocketmq/proxy/grpc/common/Converter.java | 11 + .../proxy/grpc/common/ProxyException.java | 36 +++ .../proxy/grpc/common/ProxyResponseCode.java | 29 ++ .../proxy/grpc/common/ResponseBuilder.java | 15 + .../grpc/interceptor/HeaderInterceptor.java | 4 +- .../grpc/service/ClusterGrpcService.java | 37 ++- .../grpc/service/cluster/BaseService.java | 28 ++ .../grpc/service/cluster/ConsumerService.java | 34 ++ .../grpc/service/cluster/ProducerService.java | 153 +++++++++ .../grpc/service/cluster/RouteService.java | 225 +++++++++++++ .../grpc/service/cluster/BaseServiceTest.java | 62 ++++ .../service/cluster/ProducerServiceTest.java | 304 ++++++++++++++++++ .../service/cluster/RouteServiceTest.java | 197 ++++++++++++ 19 files changed, 1164 insertions(+), 26 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java index 8850da5f5c..5c571620cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java @@ -38,11 +38,11 @@ public class ClientManager extends AbstractStartAndShutdown { this.topicRouteCache = new TopicRouteCache(this.defaultClient); - this.appendStartAndShutdown(this.clientFactory) - .appendStartAndShutdown(this.defaultClient) - .appendStartAndShutdown(this.producerClient) - .appendStartAndShutdown(this.readConsumerClient) - .appendStartAndShutdown(this.writeConsumerClient); + this.appendStartAndShutdown(this.clientFactory); + this.appendStartAndShutdown(this.defaultClient); + this.appendStartAndShutdown(this.producerClient); + this.appendStartAndShutdown(this.readConsumerClient); + this.appendStartAndShutdown(this.writeConsumerClient); } public DefaultClient getDefaultClient() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index e013cc4e4e..c7f911f685 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -18,12 +18,15 @@ package org.apache.rocketmq.proxy.client; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; +import com.google.common.hash.Hashing; +import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.common.RetainCacheLoader; import org.apache.rocketmq.proxy.common.RocketMQHelper; @@ -64,6 +67,23 @@ public class TopicRouteCache { return getCacheMessageQueueWrapper(this.topicCache, topicName); } + public AddressableMessageQueue selectOneWriteQueue(String topic, AddressableMessageQueue last) throws Exception { + if (last == null) { + return getMessageQueue(topic).getWrite().selectOne(false); + } + return getMessageQueue(topic).getWrite().selectNextOne(last); + } + + public AddressableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { + return getMessageQueue(topic).getWrite().selectOne(brokerName, queueId); + } + + public AddressableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey, AddressableMessageQueue last) throws Exception { + List writeQueues = getMessageQueue(topic).getWrite().getQueues(); + int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); + return writeQueues.get(bucket); + } + protected static MessageQueueWrapper getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { MessageQueueWrapper res = topicCache.get(key); if (res.isEmptyCachedQueue()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java index 5198d7bbfe..d93eaab979 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java @@ -44,6 +44,14 @@ public class MessageQueueWrapper { return this == EMPTY_CACHED_QUEUE; } + public SelectableMessageQueue getRead() { + return read; + } + + public SelectableMessageQueue getWrite() { + return write; + } + @Override public String toString() { return "MessageQueueWrapper{" + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java index 390b19a577..728071e4f3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java @@ -210,6 +210,14 @@ public class SelectableMessageQueue { // return newOne; // } + public List getQueues() { + return queues; + } + + public List getBrokers() { + return brokers; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java index 951ca5c5b7..9a3c69cbc5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java @@ -35,8 +35,10 @@ public class TopicRouteWrapper { this.topicRouteData = topicRouteData; this.topicName = topicName; - for (BrokerData brokerData : this.topicRouteData.getBrokerDatas()) { - brokerNameRouteData.put(brokerData.getBrokerName(), brokerData); + if (this.topicRouteData.getBrokerDatas() != null) { + for (BrokerData brokerData : this.topicRouteData.getBrokerDatas()) { + brokerNameRouteData.put(brokerData.getBrokerName(), brokerData); + } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java index 250d3b3d61..35e361fae1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java @@ -23,9 +23,8 @@ public abstract class AbstractStartAndShutdown implements StartAndShutdown { protected List startAndShutdownList = new CopyOnWriteArrayList<>(); - public AbstractStartAndShutdown appendStartAndShutdown(StartAndShutdown startAndShutdown) { + protected void appendStartAndShutdown(StartAndShutdown startAndShutdown) { this.startAndShutdownList.add(startAndShutdown); - return this; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index c04181da96..5edadf45a4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -210,6 +210,17 @@ public class Converter { return messageWithHeader.getProperties(); } + public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage) { + String topic = getResourceNameWithNamespace(protoMessage.getTopic()); + + org.apache.rocketmq.common.message.Message message = + new org.apache.rocketmq.common.message.Message(topic, protoMessage.getBody().toByteArray()); + Map messageProperty = buildMessageProperty(protoMessage); + + MessageAccessor.setProperties(message, messageProperty); + return message; + } + public static String buildExpressionType(FilterType filterType) { switch (filterType) { case SQL: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java new file mode 100644 index 0000000000..093b9424f4 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.common; + +public class ProxyException extends RuntimeException { + + private final ProxyResponseCode code; + + public ProxyException(ProxyResponseCode proxyResponseCode, String errorMessage) { + super(errorMessage); + this.code = proxyResponseCode; + } + + public ProxyException(ProxyResponseCode proxyResponseCode, String message, Throwable cause) { + super(message, cause); + this.code = proxyResponseCode; + } + + public ProxyResponseCode getCode() { + return code; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java new file mode 100644 index 0000000000..2134cb6eb3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.common; + +public enum ProxyResponseCode { + SYS_ERR, + PARAMETER_ERR, + AUTH_PERMISSION_CHECK_ERROR, + + NO_TOPIC_ROUTE, + SUBSCRIPTION_NOT_CONSISTENT, + BROKER_NOT_EXIST, + QUERY_NOT_FOUND, + SEND_MSG_FAILED; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index 25eddefd7b..11d347550c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -23,6 +23,8 @@ import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import com.google.rpc.Status; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -71,6 +73,19 @@ public class ResponseBuilder { .build(); } + public static SendMessageResponse buildSendMessageResponse(SendResult sendResult) { + if (sendResult.getSendStatus() != SendStatus.SEND_OK) { + return SendMessageResponse.newBuilder() + .setCommon(buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) + .build(); + } + return SendMessageResponse.newBuilder() + .setCommon(buildCommon(Code.OK, Code.OK.name())) + .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) + .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) + .build(); + } + public static Code buildCode(int responseCode) { Code code; switch (responseCode) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java index d09ccdadb5..64688dd728 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java @@ -29,8 +29,8 @@ import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; public class HeaderInterceptor implements ServerInterceptor { @Override - public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, - ServerCallHandler next) { + public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, + ServerCallHandler next) { SocketAddress remoteSocketAddress = call.getAttributes() .get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR); String remoteAddress = parseSocketAddress(remoteSocketAddress); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index ce739b6792..798a918523 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -54,19 +54,32 @@ import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; +import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ClusterGrpcService implements GrpcForwardService { +public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - public ClusterGrpcService() { + private final ClientManager clientManager; + private final ProducerService producerService; + private final RouteService routeService; + public ClusterGrpcService() { + this.clientManager = new ClientManager(checkData -> { + }); + this.producerService = new ProducerService(clientManager); + this.routeService = new RouteService(clientManager); + + this.appendStartAndShutdown(this.clientManager); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return null; + return this.routeService.queryRoute(ctx, request); } @Override @@ -81,15 +94,16 @@ public class ClusterGrpcService implements GrpcForwardService { @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - return null; + return this.producerService.sendMessage(ctx, request); } @Override public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return null; + return this.routeService.queryAssignment(ctx, request); } - @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + @Override + public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { return null; } @@ -128,7 +142,8 @@ public class ClusterGrpcService implements GrpcForwardService { return null; } - @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, + @Override + public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { return null; } @@ -142,12 +157,4 @@ public class ClusterGrpcService implements GrpcForwardService { ChangeInvisibleDurationRequest request) { return null; } - - @Override - public void start() throws Exception { - } - - @Override - public void shutdown() throws Exception { - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java new file mode 100644 index 0000000000..acb9691322 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -0,0 +1,28 @@ +/* + * 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.grpc.service.cluster; + +import org.apache.rocketmq.proxy.client.ClientManager; + +public class BaseService { + + protected final ClientManager clientManager; + + public BaseService(ClientManager clientManager) { + this.clientManager = clientManager; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java new file mode 100644 index 0000000000..8894c16fb7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.client.ClientManager; + +public class ConsumerService extends BaseService { + + public ConsumerService(ClientManager clientManager) { + super(clientManager); + } + + public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java new file mode 100644 index 0000000000..94c316778d --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -0,0 +1,153 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProducerService extends BaseService { + + private static final Logger log = LoggerFactory.getLogger(ProducerService.class); + + private volatile ProducerServiceHook producerServiceHook = null; + private volatile MessageQueueSelector messageQueueSelector = new DefaultMessageQueueSelector(); + + public ProducerService(ClientManager clientManager) { + super(clientManager); + } + + public interface MessageQueueSelector { + AddressableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, + org.apache.rocketmq.common.message.Message message); + } + + public class DefaultMessageQueueSelector implements MessageQueueSelector { + + @Override + public AddressableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, + org.apache.rocketmq.common.message.Message message) { + try { + String topic = requestHeader.getTopic(); + String brokerName = ""; + if (request.hasPartition()) { + brokerName = request.getPartition().getBroker().getName(); + } + Integer queueId = requestHeader.getQueueId(); + String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + AddressableMessageQueue addressableMessageQueue; + if (!StringUtils.isBlank(brokerName) && queueId != null) { + // Grpc client sendSelect situation + addressableMessageQueue = selectTargetQueue(topic, brokerName, queueId); + } else if (shardingKey != null) { + // With shardingKey + addressableMessageQueue = selectOrderQueue(topic, shardingKey); + } else { + addressableMessageQueue = selectNormalQueue(topic); + } + return addressableMessageQueue; + } catch (Exception e) { + log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); + return null; + } + } + + protected AddressableMessageQueue selectNormalQueue(String topic) throws Exception { + return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, null); + } + + protected AddressableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { + return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, brokerName, queueId); + } + + protected AddressableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { + return clientManager.getTopicRouteCache().selectOneWriteQueueByKey(topic, shardingKey, null); + } + } + + public interface ProducerServiceHook { + + void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader); + + void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader, + SendResult sendResult); + } + + public void setProducerServiceHook(ProducerServiceHook hook) { + this.producerServiceHook = hook; + } + + public void setMessageQueueSelector(MessageQueueSelector messageQueueSelector) { + this.messageQueueSelector = messageQueueSelector; + } + + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + org.apache.rocketmq.common.message.Message message = Converter.buildMessage(request.getMessage()); + CompletableFuture future = new CompletableFuture<>(); + + try { + SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); + AddressableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); + + String topic = requestHeader.getTopic(); + if (addressableMessageQueue == null) { + throw new ProxyException(ProxyResponseCode.NO_TOPIC_ROUTE, + "no writeable topic route for topic " + topic); + } + + if (producerServiceHook != null) { + producerServiceHook.beforeSend(ctx, addressableMessageQueue, message, requestHeader); + } + CompletableFuture sendResultCompletableFuture = this.clientManager.getProducerClient().sendMessage( + addressableMessageQueue.getBrokerAddr(), + addressableMessageQueue.getBrokerName(), + message, + requestHeader, + ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT + ); + sendResultCompletableFuture + .thenAccept(result -> { + if (producerServiceHook != null) { + producerServiceHook.afterSend(ctx, addressableMessageQueue, message, requestHeader, result); + } + future.complete(ResponseBuilder.buildSendMessageResponse(result)); + }) + .exceptionally(e -> { + future.completeExceptionally(e); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java new file mode 100644 index 0000000000..4bcea12cc0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -0,0 +1,225 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.Assignment; +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Endpoints; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.Permission; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.Resource; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.common.RocketMQHelper; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; + +public class RouteService extends BaseService { + + private volatile RouteAssignmentQueueSelector assignmentQueueSelector = new DefaultRouteAssignmentQueueSelector(); + private volatile QueryRouteHook queryRouteHook = null; + private volatile QueryAssignmentHook queryAssignmentHook = null; + + public RouteService(ClientManager clientManager) { + super(clientManager); + } + + public interface QueryRouteHook { + QueryRouteResponse beforeResponse(Context ctx, QueryRouteRequest request, QueryRouteResponse response); + } + + public interface QueryAssignmentHook { + QueryAssignmentResponse beforeResponse(Context ctx, QueryAssignmentRequest request, + QueryAssignmentResponse response); + } + + public interface RouteAssignmentQueueSelector { + List getAssignment(QueryAssignmentRequest request) throws Exception; + } + + public class DefaultRouteAssignmentQueueSelector implements RouteAssignmentQueueSelector { + + @Override + public List getAssignment(QueryAssignmentRequest request) throws Exception { + MessageQueueWrapper messageQueueWrapper = clientManager.getTopicRouteCache() + .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + return messageQueueWrapper.getRead().getBrokers(); + } + } + + public void setQueryRouteHook(QueryRouteHook queryRouteHook) { + this.queryRouteHook = queryRouteHook; + } + + public void setAssignmentQueueSelector(RouteAssignmentQueueSelector assignmentQueueSelector) { + this.assignmentQueueSelector = assignmentQueueSelector; + } + + public void setQueryAssignmentHook(QueryAssignmentHook queryAssignmentHook) { + this.queryAssignmentHook = queryAssignmentHook; + } + + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + CompletableFuture future = new CompletableFuture<>(); + CompletableFuture resFuture = future.thenApply(r -> { + if (this.queryRouteHook != null) { + return this.queryRouteHook.beforeResponse(ctx, request, r); + } + return r; + }); + + try { + Endpoints resEndpoints = request.getEndpoints(); + if (resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + future.complete(QueryRouteResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + request.getEndpoints() + " is invalidate")) + .build()); + return resFuture; + } + + MessageQueueWrapper messageQueueWrapper = this.clientManager.getTopicRouteCache() + .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); + List queueDataList = topicRouteData.getQueueDatas(); + + List partitionList = new ArrayList<>(); + for (QueueData queueData : queueDataList) { + Broker broker = Broker.newBuilder() + .setName(queueData.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); + + partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + } + QueryRouteResponse response = QueryRouteResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .addAllPartitions(partitionList) + .build(); + future.complete(response); + } catch (Throwable t) { + if (RocketMQHelper.isTopicNotExistError(t)) { + future.complete(QueryRouteResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.NOT_FOUND, t.getMessage())) + .build()); + } else { + future.completeExceptionally(t); + } + } + return resFuture; + } + + protected static List genPartitionFromQueueData(QueueData queueData, Resource topic, Broker broker) { + List partitionList = new ArrayList<>(); + + int r = 0; + int w = 0; + int rw = 0; + if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { + rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); + r = queueData.getReadQueueNums() - rw; + w = queueData.getWriteQueueNums() - rw; + } else if (PermName.isWriteable(queueData.getPerm())) { + w = queueData.getWriteQueueNums(); + } else if (PermName.isReadable(queueData.getPerm())) { + r = queueData.getReadQueueNums(); + } + + for (int i = 0; i < (rw + r + w); i++) { + Partition.Builder builder = Partition.newBuilder() + .setBroker(broker) + .setTopic(topic) + .setId(i); + if (i < r) { + builder.setPermission(Permission.READ); + } else if (i < w) { + builder.setPermission(Permission.WRITE); + } else { + builder.setPermission(Permission.READ_WRITE); + } + partitionList.add(builder.build()); + } + return partitionList; + } + + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + CompletableFuture future = new CompletableFuture<>(); + CompletableFuture resFuture = future.thenApply(r -> { + if (this.queryAssignmentHook != null) { + return this.queryAssignmentHook.beforeResponse(ctx, request, r); + } + return r; + }); + try { + Endpoints resEndpoints = request.getEndpoints(); + if (resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + future.complete(QueryAssignmentResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + request.getEndpoints() + " is invalidate")) + .build()); + return resFuture; + } + + List assignments = new ArrayList<>(); + List messageQueueList = this.assignmentQueueSelector.getAssignment(request); + + for (AddressableMessageQueue messageQueue : messageQueueList) { + Broker broker = Broker.newBuilder() + .setName(messageQueue.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); + + Partition defaultPartition = Partition.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(Permission.READ_WRITE) + .setBroker(broker) + .build(); + + assignments.add(Assignment.newBuilder() + .setPartition(defaultPartition) + .build()); + } + QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() + .addAllAssignments(assignments) + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + if (this.queryAssignmentHook != null) { + this.queryAssignmentHook.beforeResponse(ctx, request, response); + } + future.complete(response); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return resFuture; + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java new file mode 100644 index 0000000000..fd220378a0 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.DefaultClient; +import org.apache.rocketmq.proxy.client.ProducerClient; +import org.apache.rocketmq.proxy.client.ReadConsumerClient; +import org.apache.rocketmq.proxy.client.TopicRouteCache; +import org.apache.rocketmq.proxy.client.WriteConsumerClient; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.when; + +@Ignore +@RunWith(MockitoJUnitRunner.Silent.class) +public abstract class BaseServiceTest { + + @Mock + protected ClientManager clientManager; + @Mock + protected DefaultClient defaultClient; + @Mock + protected ProducerClient producerClient; + @Mock + protected ReadConsumerClient readConsumerClient; + @Mock + protected WriteConsumerClient writeConsumerClient; + @Mock + protected TopicRouteCache topicRouteCache; + + @Before + public void before() throws Throwable { + when(clientManager.getDefaultClient()).thenReturn(defaultClient); + when(clientManager.getProducerClient()).thenReturn(producerClient); + when(clientManager.getReadConsumerClient()).thenReturn(readConsumerClient); + when(clientManager.getWriteConsumerClient()).thenReturn(writeConsumerClient); + when(clientManager.getTopicRouteCache()).thenReturn(topicRouteCache); + + beforeEach(); + } + + public abstract void beforeEach() throws Throwable; +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java new file mode 100644 index 0000000000..4165ad8d69 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -0,0 +1,304 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.ByteString; +import com.google.rpc.Code; +import io.grpc.Context; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; +import org.junit.Test; + +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.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.when; + +public class ProducerServiceTest extends BaseServiceTest { + + @Override + public void beforeEach() throws Throwable { + AddressableMessageQueue queue = new AddressableMessageQueue( + new MessageQueue("topic", "selectOrderQueue", 0), + "selectOrderQueueAddr"); + when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString(), isNull())) + .thenReturn(queue); + + queue = new AddressableMessageQueue( + new MessageQueue("topic", "selectTargetQueue", 0), + "selectTargetQueueAddr"); + when(topicRouteCache.selectOneWriteQueue(anyString(), anyString(), anyInt())) + .thenReturn(queue); + + queue = new AddressableMessageQueue( + new MessageQueue("topic", "selectNormalQueue", 0), + "selectNormalQueueAddr"); + when(topicRouteCache.selectOneWriteQueue(anyString(), isNull())) + .thenReturn(queue); + } + + @Test + public void testSendOrderMessageWithShardingKey() { + CompletableFuture sendResultFuture = new CompletableFuture<>(); + when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + .thenReturn(sendResultFuture); + sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), + 1L, "txId", "offsetMsgId", "regionId")); + + ProducerService producerService = new ProducerService(this.clientManager); + + AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference messageRef = new AtomicReference<>(); + producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { + @Override + public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { + selectQueueRef.set(addressableMessageQueue); + } + + @Override + public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, + SendResult sendResult) { + + } + }); + + CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build()); + + try { + SendMessageResponse response = future.get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals("msgId", response.getMessageId()); + assertEquals("selectOrderQueue", selectQueueRef.get().getBrokerName()); + assertEquals("selectOrderQueueAddr", selectQueueRef.get().getBrokerAddr()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testSendNormalMessage() { + CompletableFuture sendResultFuture = new CompletableFuture<>(); + when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + .thenReturn(sendResultFuture); + sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), + 1L, "txId", "offsetMsgId", "regionId")); + + ProducerService producerService = new ProducerService(this.clientManager); + + AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference messageRef = new AtomicReference<>(); + producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { + @Override + public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { + selectQueueRef.set(addressableMessageQueue); + } + + @Override + public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, + SendResult sendResult) { + + } + }); + + CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build()); + + try { + SendMessageResponse response = future.get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals("msgId", response.getMessageId()); + assertEquals("selectNormalQueue", selectQueueRef.get().getBrokerName()); + assertEquals("selectNormalQueueAddr", selectQueueRef.get().getBrokerAddr()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testSendOrderMessageSelectQueue() { + CompletableFuture sendResultFuture = new CompletableFuture<>(); + when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + .thenReturn(sendResultFuture); + sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), + 1L, "txId", "offsetMsgId", "regionId")); + + ProducerService producerService = new ProducerService(this.clientManager); + + AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference messageRef = new AtomicReference<>(); + producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { + @Override + public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { + selectQueueRef.set(addressableMessageQueue); + } + + @Override + public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, + SendResult sendResult) { + + } + }); + + CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .setPartitionId(1) + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .setPartition(Partition.newBuilder() + .setBroker(Broker.newBuilder() + .setName("brokerName") + .build()) + .build()) + .build()); + + try { + SendMessageResponse response = future.get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals("msgId", response.getMessageId()); + assertEquals("selectTargetQueue", selectQueueRef.get().getBrokerName()); + assertEquals("selectTargetQueueAddr", selectQueueRef.get().getBrokerAddr()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testSendMessageNoQueueSelect() { + ProducerService producerService = new ProducerService(this.clientManager); + + producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> null); + + CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build()); + + try { + SendMessageResponse response = future.get(); + assertNull(response); + } catch (Exception e) { + assertNotNull(e); + assertTrue(e instanceof ExecutionException); + assertTrue(e.getCause() instanceof ProxyException); + assertEquals(ProxyResponseCode.NO_TOPIC_ROUTE, ((ProxyException)e.getCause()).getCode()); + } + } + + @Test + public void testSendMessageWithError() { + RuntimeException ex = new RuntimeException(); + + CompletableFuture sendResultFuture = new CompletableFuture<>(); + when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + .thenReturn(sendResultFuture); + sendResultFuture.completeExceptionally(ex); + + ProducerService producerService = new ProducerService(this.clientManager); + + CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build()); + + try { + SendMessageResponse response = future.get(); + assertNull(response); + } catch (Exception e) { + assertNotNull(e); + assertTrue(e instanceof ExecutionException); + assertSame(ex, e.getCause()); + } + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java new file mode 100644 index 0000000000..39ee582e6a --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -0,0 +1,197 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Address; +import apache.rocketmq.v1.AddressScheme; +import apache.rocketmq.v1.Endpoints; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.Resource; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +public class RouteServiceTest extends BaseServiceTest { + + @Override + public void beforeEach() throws Throwable { + TopicRouteData routeData = new TopicRouteData(); + + List brokerDataList = new ArrayList<>(); + BrokerData brokerData = new BrokerData(); + brokerData.setCluster("cluster"); + brokerData.setBrokerName("brokerName"); + HashMap brokerAddrs = new HashMap() {{ + put(0L, "127.0.0.1:10911"); + }}; + brokerData.setBrokerAddrs(brokerAddrs); + brokerDataList.add(brokerData); + + List queueDataList = new ArrayList<>(); + QueueData queueData = new QueueData(); + queueData.setPerm(6); + queueData.setWriteQueueNums(8); + queueData.setReadQueueNums(8); + queueData.setBrokerName("brokerName"); + queueDataList.add(queueData); + + routeData.setBrokerDatas(brokerDataList); + routeData.setQueueDatas(queueDataList); + + MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); + when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); + + when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + } + + @Test + public void testQueryRouteWithInvalidEndpoints() { + RouteService routeService = new RouteService(this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRoute() { + RouteService routeService = new RouteService(this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(8, response.getPartitionsCount()); + assertEquals("host", response.getPartitions(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRouteWhenTopicNotExist() { + RouteService routeService = new RouteService(this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("notExistTopic") + .build()) + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRouteHook() { + RouteService routeService = new RouteService(this.clientManager); + + routeService.setQueryRouteHook((ctx, request, response) -> QueryRouteResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.NOT_FOUND, Code.NOT_FOUND.name())) + .build()); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryAssignmentInvalidEndpoints() { + RouteService routeService = new RouteService(this.clientManager); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .build()); + + try { + QueryAssignmentResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryAssignment() { + RouteService routeService = new RouteService(this.clientManager); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setClientId("clientId") + .build()); + + try { + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); + assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } +} \ No newline at end of file From be512d57470dbf61d84b8339bb831802e99ea978 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 15:32:03 +0800 Subject: [PATCH 023/338] [ISSUE #3949] refactor SelectableMessageQueue and do the merging work. --- .../proxy/client/TopicRouteCache.java | 2 +- .../client/route/SelectableMessageQueue.java | 24 +++---------------- .../grpc/service/cluster/ConsumerService.java | 2 +- .../grpc/service/cluster/RouteService.java | 2 +- 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index c7f911f685..dec5496668 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -71,7 +71,7 @@ public class TopicRouteCache { if (last == null) { return getMessageQueue(topic).getWrite().selectOne(false); } - return getMessageQueue(topic).getWrite().selectNextOne(last); + return getMessageQueue(topic).getWrite().selectNextQueue(last); } public AddressableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java index 728071e4f3..88f7b3cee8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java @@ -119,7 +119,7 @@ public class SelectableMessageQueue { AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), brokerAddr); - queueSet.add(mq); + queueSet.add(mq); } } } @@ -128,8 +128,6 @@ public class SelectableMessageQueue { return queueSet.stream().sorted().collect(Collectors.toList()); } - - // 这里应该不是线程安全的 private void buildBrokerActingQueues(String topic, List normalQueues) { for (AddressableMessageQueue mq : normalQueues) { AddressableMessageQueue brokerActingQueue = new AddressableMessageQueue( @@ -194,28 +192,12 @@ public class SelectableMessageQueue { return newOne; } - // should use selectNextQueue -// public final AddressableMessageQueue selectNextBrokerActingQueue(AddressableMessageQueue last) { -// boolean onlyBroker = last.getQueueId() < 0; -// AddressableMessageQueue newOne = last; -// int count = onlyBroker ? brokerActingQueues.size() : queues.size(); -// -// for (int i = 0; i < count; i++) { -// newOne = selectOne(onlyBroker); -// if (!newOne.getBrokerName().equals(last.getBrokerName())) { -// break; -// } -// } -// -// return newOne; -// } - public List getQueues() { return queues; } - public List getBrokers() { - return brokers; + public List getBrokerActingQueues() { + return brokerActingQueues; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 8894c16fb7..7aa6887443 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -29,6 +29,6 @@ public class ConsumerService extends BaseService { } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - + return null; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 4bcea12cc0..6bb10534bc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -70,7 +70,7 @@ public class RouteService extends BaseService { public List getAssignment(QueryAssignmentRequest request) throws Exception { MessageQueueWrapper messageQueueWrapper = clientManager.getTopicRouteCache() .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); - return messageQueueWrapper.getRead().getBrokers(); + return messageQueueWrapper.getRead().getBrokerActingQueues(); } } From 3b437435b479d614bfcbaebc38d10c2de5abbc2b Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 16:46:29 +0800 Subject: [PATCH 024/338] [ISSUE #3949] do some renaming work. --- .../apache/rocketmq/proxy/ProxyStartup.java | 4 +- .../proxy/channel/ChannelManager.java | 5 +- ...Client.java => AbstractForwardClient.java} | 13 +- .../rocketmq/proxy/client/ClientManager.java | 67 ----- ...tClient.java => DefaultForwardClient.java} | 19 +- .../proxy/client/ForwardClientManager.java | 71 ++++++ ...oducerClient.java => ForwardProducer.java} | 13 +- ...erClient.java => ForwardReadConsumer.java} | 11 +- ...rClient.java => ForwardWriteConsumer.java} | 11 +- .../proxy/client/TopicRouteCache.java | 26 +- .../AbstractMQClientFactory.java} | 10 +- .../ForwardClientFactory.java} | 28 +-- .../MQClientFactory.java} | 6 +- .../MQClientFactoryImpl.java} | 6 +- .../TransactionalProducerFactory.java} | 11 +- .../DoNothingClientRemotingProcessor.java | 3 +- .../ProxyClientRemotingProcessor.java | 18 +- .../client/route/AddressableMessageQueue.java | 80 ------ .../client/route/MessageQueueSelector.java | 229 ++++++++++++++++++ .../client/route/MessageQueueWrapper.java | 24 +- .../client/route/SelectableMessageQueue.java | 219 +++-------------- .../client/transaction/TransactionId.java | 18 +- .../TransactionStateCheckRequest.java | 10 +- .../transaction/TransactionStateChecker.java | 1 - .../proxy/configuration/ProxyConfig.java | 90 +++---- .../grpc/service/ClusterGrpcService.java | 6 +- .../grpc/service/cluster/BaseService.java | 6 +- .../grpc/service/cluster/ConsumerService.java | 4 +- .../grpc/service/cluster/ProducerService.java | 26 +- .../grpc/service/cluster/RouteService.java | 16 +- .../proxy/client/ClientManagerTest.java | 20 +- .../grpc/service/cluster/BaseServiceTest.java | 28 +-- .../service/cluster/ProducerServiceTest.java | 26 +- 33 files changed, 577 insertions(+), 548 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{BaseClient.java => AbstractForwardClient.java} (76%) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{DefaultClient.java => DefaultForwardClient.java} (77%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{ProducerClient.java => ForwardProducer.java} (84%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{ReadConsumerClient.java => ForwardReadConsumer.java} (84%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{WriteConsumerClient.java => ForwardWriteConsumer.java} (86%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{mqconstructor/AbstractRocketMQClientConstructor.java => factory/AbstractMQClientFactory.java} (86%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{ClientFactory.java => factory/ForwardClientFactory.java} (69%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{mqconstructor/RocketMQClientConstructor.java => factory/MQClientFactory.java} (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{mqconstructor/MQClientAPIConstructor.java => factory/MQClientFactoryImpl.java} (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/client/{mqconstructor/TransactionClientConstructor.java => factory/TransactionalProducerFactory.java} (74%) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueSelector.java 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 e70a227cbd..8379fcf66c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -108,7 +108,7 @@ public class ProxyStartup { private static void initThreadPoolMonitor() { ThreadPoolMonitor.init(); ProxyConfig config = ConfigurationManager.getProxyConfig(); - ThreadPoolMonitor.config(config.isEnablePrintJstack(), config.getPrintJstackPeriodMillis()); + ThreadPoolMonitor.config(config.isEnablePrintJstack(), config.getPrintJstackInMillis()); } private static void initLogger() throws JoranException { @@ -120,6 +120,6 @@ public class ProxyStartup { lc.reset(); //https://logback.qos.ch/manual/configuration.html lc.setPackagingDataEnabled(false); - configurator.doConfigure(ConfigurationManager.getProxyHome() + "/conf/logback.xml"); + configurator.doConfigure(ConfigurationManager.getProxyHome() + "/conf/logback_proxy.xml"); } } \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 2c9ff07d9a..d8666fa5b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -63,7 +63,7 @@ public class ChannelManager { .get(InterceptorConstants.REMOTE_ADDRESS); final String localAddress = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.LOCAL_ADDRESS); - return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getExpiredChannelTimeSec()); + return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds()); } /** @@ -71,8 +71,7 @@ public class ChannelManager { */ public void scanAndCleanChannels() { try { - Iterator> iterator = clientIdChannelMap.entrySet() - .iterator(); + Iterator> iterator = clientIdChannelMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); if (!entry.getValue() diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java similarity index 76% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java index 270e1ae825..480554d6b8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/BaseClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java @@ -18,20 +18,21 @@ package org.apache.rocketmq.proxy.client; import java.util.concurrent.ThreadLocalRandom; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; -public abstract class BaseClient implements StartAndShutdown { +public abstract class AbstractForwardClient implements StartAndShutdown { - private final ClientFactory clientFactory; + private final ForwardClientFactory forwardClientFactory; private MQClientAPIExtImpl[] clients; - public BaseClient(ClientFactory clientFactory) { - this.clientFactory = clientFactory; + public AbstractForwardClient(ForwardClientFactory forwardClientFactory) { + this.forwardClientFactory = forwardClientFactory; } protected abstract int getClientNum(); - protected abstract MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name); + protected abstract MQClientAPIExtImpl createNewClient(ForwardClientFactory forwardClientFactory, String name); protected abstract String getNamePrefix(); @@ -48,7 +49,7 @@ public abstract class BaseClient implements StartAndShutdown { this.clients = new MQClientAPIExtImpl[clientCount]; for (int i = 0; i < clientCount; i++) { String name = getNamePrefix() + "N_" + i; - clients[i] = createNewClient(clientFactory, name); + clients[i] = createNewClient(forwardClientFactory, name); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java deleted file mode 100644 index 5c571620cd..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientManager.java +++ /dev/null @@ -1,67 +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.proxy.client; - -import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; - -public class ClientManager extends AbstractStartAndShutdown { - - private final ClientFactory clientFactory; - private final DefaultClient defaultClient; - private final ProducerClient producerClient; - private final ReadConsumerClient readConsumerClient; - private final WriteConsumerClient writeConsumerClient; - - private final TopicRouteCache topicRouteCache; - - public ClientManager(TransactionStateChecker transactionStateChecker) { - this.clientFactory = new ClientFactory(transactionStateChecker); - this.defaultClient = new DefaultClient(this.clientFactory); - this.producerClient = new ProducerClient(this.clientFactory); - this.readConsumerClient = new ReadConsumerClient(this.clientFactory); - this.writeConsumerClient = new WriteConsumerClient(this.clientFactory); - - this.topicRouteCache = new TopicRouteCache(this.defaultClient); - - this.appendStartAndShutdown(this.clientFactory); - this.appendStartAndShutdown(this.defaultClient); - this.appendStartAndShutdown(this.producerClient); - this.appendStartAndShutdown(this.readConsumerClient); - this.appendStartAndShutdown(this.writeConsumerClient); - } - - public DefaultClient getDefaultClient() { - return defaultClient; - } - - public ProducerClient getProducerClient() { - return producerClient; - } - - public ReadConsumerClient getReadConsumerClient() { - return readConsumerClient; - } - - public WriteConsumerClient getWriteConsumerClient() { - return writeConsumerClient; - } - - public TopicRouteCache getTopicRouteCache() { - return topicRouteCache; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java similarity index 77% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java index 4ab7518eb4..de3d950160 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java @@ -22,25 +22,25 @@ import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.remoting.exception.RemotingException; -public class DefaultClient extends BaseClient { - +public class DefaultForwardClient extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; - public DefaultClient(ClientFactory clientFactory) { + public DefaultForwardClient(ForwardClientFactory clientFactory) { super(clientFactory); } @Override protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getDefaultClientNum(); + return ConfigurationManager.getProxyConfig().getDefaultForwardClientNum(); } @Override - protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getDefaultClientWorkerFactor(); + protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getDefaultForwardClientWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getMQClient(name, threadCount); @@ -51,12 +51,13 @@ public class DefaultClient extends BaseClient { return CID_PREFIX; } - public CompletableFuture> getConsumerListByGroup(String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, - long timeoutMillis) { + public CompletableFuture> getConsumerListByGroup( + String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis) { return getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); } - public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { + public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) + throws RemotingException, InterruptedException, MQClientException { return getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java new file mode 100644 index 0000000000..85dc298a8b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java @@ -0,0 +1,71 @@ +/* + * 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.client; + +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; + +public class ForwardClientManager extends AbstractStartAndShutdown { + private final ForwardClientFactory forwardClientFactory; + private final DefaultForwardClient defaultForwardClient; + private final ForwardProducer forwardProducer; + private final ForwardReadConsumer forwardReadConsumer; + private final ForwardWriteConsumer forwardWriteConsumer; + + private final TopicRouteCache topicRouteCache; + + public ForwardClientManager(TransactionStateChecker transactionStateChecker) { + this.forwardClientFactory = new ForwardClientFactory(transactionStateChecker); + this.defaultForwardClient = new DefaultForwardClient(this.forwardClientFactory); + this.forwardProducer = new ForwardProducer(this.forwardClientFactory); + this.forwardReadConsumer = new ForwardReadConsumer(this.forwardClientFactory); + this.forwardWriteConsumer = new ForwardWriteConsumer(this.forwardClientFactory); + + this.topicRouteCache = new TopicRouteCache(this.defaultForwardClient); + + this.appendStartAndShutdown(this.forwardClientFactory); + this.appendStartAndShutdown(this.defaultForwardClient); + this.appendStartAndShutdown(this.forwardProducer); + this.appendStartAndShutdown(this.forwardReadConsumer); + this.appendStartAndShutdown(this.forwardWriteConsumer); + } + + public ForwardClientFactory getForwardClientFactory() { + return forwardClientFactory; + } + + public DefaultForwardClient getDefaultForwardClient() { + return defaultForwardClient; + } + + public ForwardProducer getForwardProducer() { + return forwardProducer; + } + + public ForwardReadConsumer getForwardReadConsumer() { + return forwardReadConsumer; + } + + public ForwardWriteConsumer getForwardWriteConsumer() { + return forwardWriteConsumer; + } + + public TopicRouteCache getTopicRouteCache() { + return topicRouteCache; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java similarity index 84% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java index 668cb7fce8..8254b83fb1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ProducerClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java @@ -23,28 +23,29 @@ import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class ProducerClient extends BaseClient { +public class ForwardProducer extends AbstractForwardClient { private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; - public ProducerClient(ClientFactory clientFactory) { + public ForwardProducer(ForwardClientFactory clientFactory) { super(clientFactory); } @Override protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getProducerClientNum(); + return ConfigurationManager.getProxyConfig().getForwardProducerNum(); } @Override - protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { - double sendClientWorkerFactor = ConfigurationManager.getProxyConfig().getProducerClientWorkerFactor(); + protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + double sendClientWorkerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * sendClientWorkerFactor); - return clientFactory.getTransactionClient(name, threadCount); + return clientFactory.getTransactionalProducer(name, threadCount); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java similarity index 84% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java index 60516f9534..f3672ea370 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ReadConsumerClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java @@ -22,24 +22,25 @@ import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -public class ReadConsumerClient extends BaseClient { +public class ForwardReadConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_CONSUME_MESSAGE_"; - public ReadConsumerClient(ClientFactory clientFactory) { + public ForwardReadConsumer(ForwardClientFactory clientFactory) { super(clientFactory); } @Override protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getConsumerClientNum(); + return ConfigurationManager.getProxyConfig().getForwardConsumerNum(); } @Override - protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getConsumerClientWorkerFactor(); + protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getMQClient(name, threadCount); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java index ee04262163..26dedbbd0d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/WriteConsumerClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java @@ -22,25 +22,26 @@ import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; +import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.remoting.exception.RemotingException; -public class WriteConsumerClient extends BaseClient { +public class ForwardWriteConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DELETE_MESSAGE_"; - public WriteConsumerClient(ClientFactory clientFactory) { + public ForwardWriteConsumer(ForwardClientFactory clientFactory) { super(clientFactory); } @Override protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getConsumerClientNum(); + return ConfigurationManager.getProxyConfig().getForwardConsumerNum(); } @Override - protected MQClientAPIExtImpl createNewClient(ClientFactory clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getConsumerClientWorkerFactor(); + protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getMQClient(name, threadCount); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index dec5496668..33091ce136 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -26,7 +26,7 @@ import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.common.RetainCacheLoader; import org.apache.rocketmq.proxy.common.RocketMQHelper; @@ -43,9 +43,9 @@ public class TopicRouteCache { private final LoadingCache topicCache; private final ThreadPoolExecutor cacheRefreshExecutor; - private final DefaultClient defaultClient; + private final DefaultForwardClient defaultClient; - public TopicRouteCache(DefaultClient defaultClient) { + public TopicRouteCache(DefaultForwardClient defaultClient) { ProxyConfig config = ConfigurationManager.getProxyConfig(); this.defaultClient = defaultClient; @@ -59,7 +59,7 @@ public class TopicRouteCache { ); this.topicCache = CacheBuilder.newBuilder() .maximumSize(config.getTopicRouteCacheMaxNum()) - .refreshAfterWrite(config.getTopicRouteCacheExpireSecond(), TimeUnit.SECONDS) + .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new TopicRouteCacheLoader()); } @@ -67,19 +67,19 @@ public class TopicRouteCache { return getCacheMessageQueueWrapper(this.topicCache, topicName); } - public AddressableMessageQueue selectOneWriteQueue(String topic, AddressableMessageQueue last) throws Exception { + public SelectableMessageQueue selectOneWriteQueue(String topic, SelectableMessageQueue last) throws Exception { if (last == null) { - return getMessageQueue(topic).getWrite().selectOne(false); + return getMessageQueue(topic).getWriteSelector().selectOne(false); } - return getMessageQueue(topic).getWrite().selectNextQueue(last); + return getMessageQueue(topic).getWriteSelector().selectNextQueue(last); } - public AddressableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { - return getMessageQueue(topic).getWrite().selectOne(brokerName, queueId); + public SelectableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { + return getMessageQueue(topic).getWriteSelector().selectOne(brokerName, queueId); } - public AddressableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey, AddressableMessageQueue last) throws Exception { - List writeQueues = getMessageQueue(topic).getWrite().getQueues(); + public SelectableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey, SelectableMessageQueue last) throws Exception { + List writeQueues = getMessageQueue(topic).getWriteSelector().getQueues(); int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); return writeQueues.get(bucket); } @@ -122,10 +122,10 @@ public class TopicRouteCache { log.info("load {} from namesrv. topic: {}, queue: {}", loaderName(), topic, tmp); return tmp; } - return MessageQueueWrapper.EMPTY_CACHED_QUEUE; + return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; } catch (Exception e) { if (RocketMQHelper.isTopicNotExistError(e)) { - return MessageQueueWrapper.EMPTY_CACHED_QUEUE; + return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; } throw e; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java index 4e530cacf8..35221594f1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/AbstractRocketMQClientConstructor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.mqconstructor; +package org.apache.rocketmq.proxy.client.factory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -23,14 +23,14 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class AbstractRocketMQClientConstructor implements RocketMQClientConstructor { +public abstract class AbstractMQClientFactory implements MQClientFactory { - private static final Logger log = LoggerFactory.getLogger(AbstractRocketMQClientConstructor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMQClientFactory.class); protected Map cacheTable = new ConcurrentHashMap<>(); protected RPCHook rpcHook; - public AbstractRocketMQClientConstructor(RPCHook rpcHook) { + public AbstractMQClientFactory(RPCHook rpcHook) { this.rpcHook = rpcHook; } @@ -78,7 +78,7 @@ public abstract class AbstractRocketMQClientConstructor implements RocketMQCl try { this.shutdown(v); } catch (Exception e) { - log.warn("RocketMQClientConstructor shutdown all err.", e); + LOGGER.warn("RocketMQClientConstructor shutdown all err.", e); } }); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java similarity index 69% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java index 5e777eef30..55e709cb4d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java @@ -14,37 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.client.factory; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.proxy.client.mqconstructor.MQClientAPIConstructor; -import org.apache.rocketmq.proxy.client.mqconstructor.TransactionClientConstructor; import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.remoting.RPCHook; -public class ClientFactory implements StartAndShutdown { +public class ForwardClientFactory implements StartAndShutdown { private RPCHook rpcHook = null; - private final MQClientAPIConstructor mqClientAPIConstructor; - private final TransactionClientConstructor transactionClientConstructor; + private final MQClientFactoryImpl mqClientFactory; + private final TransactionalProducerFactory transactionalProducerFactory; - public ClientFactory(TransactionStateChecker transactionStateChecker) { + public ForwardClientFactory(TransactionStateChecker transactionStateChecker) { this.init(); - this.mqClientAPIConstructor = new MQClientAPIConstructor(this.rpcHook); - this.transactionClientConstructor = new TransactionClientConstructor(this.rpcHook); + this.mqClientFactory = new MQClientFactoryImpl(this.rpcHook); + this.transactionalProducerFactory = new TransactionalProducerFactory(this.rpcHook, transactionStateChecker); } private void init() { System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); - if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvAddr())) { + if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvDomain())) { System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, ConfigurationManager.getProxyConfig().getNameSrvAddr()); } else { System.setProperty("rocketmq.namesrv.domain", ConfigurationManager.getProxyConfig().getNameSrvDomain()); @@ -53,11 +51,11 @@ public class ClientFactory implements StartAndShutdown { } public MQClientAPIExtImpl getMQClient(String instanceName, int bootstrapWorkerThreads) { - return mqClientAPIConstructor.getOne(instanceName, bootstrapWorkerThreads); + return mqClientFactory.getOne(instanceName, bootstrapWorkerThreads); } - public MQClientAPIExtImpl getTransactionClient(String instanceName, int bootstrapWorkerThreads) { - return transactionClientConstructor.getOne(instanceName, bootstrapWorkerThreads); + public MQClientAPIExtImpl getTransactionalProducer(String instanceName, int bootstrapWorkerThreads) { + return transactionalProducerFactory.getOne(instanceName, bootstrapWorkerThreads); } public void setRpcHook(RPCHook rpcHook) { @@ -71,7 +69,7 @@ public class ClientFactory implements StartAndShutdown { @Override public void shutdown() throws Exception { - this.mqClientAPIConstructor.shutdownAll(); - this.transactionClientConstructor.shutdownAll(); + this.mqClientFactory.shutdownAll(); + this.transactionalProducerFactory.shutdownAll(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java index 2dd0378e7e..de43082292 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/RocketMQClientConstructor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java @@ -14,11 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.mqconstructor; - -public interface RocketMQClientConstructor { +package org.apache.rocketmq.proxy.client.factory; +public interface MQClientFactory { T getOne(String instanceName, int bootstrapWorkerThreads); - void shutdownAll(); } \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java index f3e276c7a7..d4a4979c24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/MQClientAPIConstructor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java @@ -14,16 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.mqconstructor; +package org.apache.rocketmq.proxy.client.factory; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.proxy.client.processor.DoNothingClientRemotingProcessor; import org.apache.rocketmq.remoting.RPCHook; -public class MQClientAPIConstructor extends AbstractRocketMQClientConstructor { +public class MQClientFactoryImpl extends AbstractMQClientFactory { - public MQClientAPIConstructor(RPCHook rpcHook) { + public MQClientFactoryImpl(RPCHook rpcHook) { super(rpcHook); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java similarity index 74% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java index 67f8fb62bd..6168e9e358 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/mqconstructor/TransactionClientConstructor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java @@ -14,24 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.mqconstructor; +package org.apache.rocketmq.proxy.client.factory; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.proxy.client.processor.ProxyClientRemotingProcessor; +import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; import org.apache.rocketmq.remoting.RPCHook; -public class TransactionClientConstructor extends AbstractRocketMQClientConstructor { +public class TransactionalProducerFactory extends AbstractMQClientFactory { + private final TransactionStateChecker transactionStateChecker; - public TransactionClientConstructor(RPCHook rpcHook) { + public TransactionalProducerFactory(RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { super(rpcHook); + this.transactionStateChecker = transactionStateChecker; } @Override MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { return new MQClientAPIExtImpl( createNettyClientConfig(bootstrapWorkerThreads), - new ProxyClientRemotingProcessor(null), + new ProxyClientRemotingProcessor(this.transactionStateChecker), rpcHook, new ClientConfig()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java index 2f9d100f72..74c5874370 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/DoNothingClientRemotingProcessor.java @@ -23,8 +23,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class DoNothingClientRemotingProcessor extends ClientRemotingProcessor { - public DoNothingClientRemotingProcessor( - MQClientInstance mqClientFactory) { + public DoNothingClientRemotingProcessor(MQClientInstance mqClientFactory) { super(mqClientFactory); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java index 07361919b0..bb5fe37ae5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/processor/ProxyClientRemotingProcessor.java @@ -31,17 +31,18 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { - private final TransactionStateChecker transactionStateChecker; - public ProxyClientRemotingProcessor( - TransactionStateChecker transactionStateChecker) { + public ProxyClientRemotingProcessor(TransactionStateChecker transactionStateChecker) { super(null); this.transactionStateChecker = transactionStateChecker; } @Override - public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { + public RemotingCommand processRequest( + ChannelHandlerContext ctx, + RemotingCommand request + ) throws RemotingCommandException { if (request.getCode() == RequestCode.CHECK_TRANSACTION_STATE) { return this.checkTransactionState(ctx, request); } @@ -49,9 +50,12 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { } @Override - public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, - RemotingCommand request) throws RemotingCommandException { - final CheckTransactionStateRequestHeader requestHeader = (CheckTransactionStateRequestHeader) request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + public RemotingCommand checkTransactionState( + ChannelHandlerContext ctx, + RemotingCommand request + ) throws RemotingCommandException { + final CheckTransactionStateRequestHeader requestHeader = + (CheckTransactionStateRequestHeader) request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); final ByteBuffer byteBuffer = ByteBuffer.wrap(request.getBody()); final MessageExt messageExt = MessageDecoder.decode(byteBuffer, true, false, false); if (messageExt != null) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java deleted file mode 100644 index ee6db196e3..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/AddressableMessageQueue.java +++ /dev/null @@ -1,80 +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.proxy.client.route; - -import java.util.Objects; -import org.apache.rocketmq.common.message.MessageQueue; - -public class AddressableMessageQueue implements Comparable { - - private final MessageQueue messageQueue; - private final String brokerAddr; - - public AddressableMessageQueue(MessageQueue messageQueue, String brokerAddr) { - this.messageQueue = messageQueue; - this.brokerAddr = brokerAddr; - } - - @Override - public int compareTo(AddressableMessageQueue o) { - return messageQueue.compareTo(o.messageQueue); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof AddressableMessageQueue)) { - return false; - } - AddressableMessageQueue queue = (AddressableMessageQueue) o; - return Objects.equals(messageQueue, queue.messageQueue); - } - - @Override - public int hashCode() { - return messageQueue == null ? 1 : messageQueue.hashCode(); - } - - public int getQueueId() { - return this.messageQueue.getQueueId(); - } - - public String getBrokerName() { - return this.messageQueue.getBrokerName(); - } - - public String getTopic() { - return messageQueue.getTopic(); - } - - public MessageQueue getMessageQueue() { - return messageQueue; - } - - public String getBrokerAddr() { - return brokerAddr; - } - - @Override public String toString() { - return "AddressableMessageQueue{" + - "messageQueue=" + messageQueue + - ", brokerAddr='" + brokerAddr + '\'' + - '}'; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueSelector.java new file mode 100644 index 0000000000..d88f560a31 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueSelector.java @@ -0,0 +1,229 @@ +/* + * 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.client.route; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.route.QueueData; + +public class MessageQueueSelector { + private static final int BROKER_ACTING_QUEUE_ID = -1; + + // multiple queues for one broker, with queueId : normal + private final List queues = new ArrayList<>(); + // one queue for one broker, with queueId : -1 + private final List brokerActingQueues = new ArrayList<>(); + private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); + private final AtomicInteger queueIndex; + private final AtomicInteger brokerIndex; + + public MessageQueueSelector(TopicRouteWrapper topicRouteWrapper, boolean read) { + if (read) { + this.queues.addAll(buildRead(topicRouteWrapper)); + } else { + this.queues.addAll(buildWrite(topicRouteWrapper)); + } + buildBrokerActingQueues(topicRouteWrapper.getTopicName(), this.queues); + + this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + this.brokerIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + } + + private static List buildRead(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); + List qds = topicRoute.getQueueDatas(); + if (qds == null) { + return new ArrayList<>(); + } + + for (QueueData qd : qds) { + if (PermName.isReadable(qd.getPerm())) { + String brokerAddr = topicRoute.getMasterAddrPrefer(qd.getBrokerName()); + if (brokerAddr == null) { + continue; + } + + for (int i = 0; i < qd.getReadQueueNums(); i++) { + SelectableMessageQueue mq = new SelectableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), + brokerAddr); + queueSet.add(mq); + } + } + } + + return queueSet.stream().sorted().collect(Collectors.toList()); + } + + private static List buildWrite(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); + // order topic route. + if (StringUtils.isNotBlank(topicRoute.getOrderTopicConf())) { + String[] brokers = topicRoute.getOrderTopicConf().split(";"); + for (String broker : brokers) { + String[] item = broker.split(":"); + String brokerName = item[0]; + String brokerAddr = topicRoute.getMasterAddr(brokerName); + if (brokerAddr == null) { + continue; + } + + int nums = Integer.parseInt(item[1]); + for (int i = 0; i < nums; i++) { + SelectableMessageQueue mq = new SelectableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), brokerName, i), + brokerAddr); + queueSet.add(mq); + } + } + } else { + List qds = topicRoute.getQueueDatas(); + if (qds == null) { + return new ArrayList<>(); + } + + for (QueueData qd : qds) { + if (PermName.isWriteable(qd.getPerm())) { + String brokerAddr = topicRoute.getMasterAddr(qd.getBrokerName()); + if (brokerAddr == null) { + continue; + } + + for (int i = 0; i < qd.getWriteQueueNums(); i++) { + SelectableMessageQueue mq = new SelectableMessageQueue( + new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), + brokerAddr); + queueSet.add(mq); + } + } + } + } + + return queueSet.stream().sorted().collect(Collectors.toList()); + } + + private void buildBrokerActingQueues(String topic, List normalQueues) { + for (SelectableMessageQueue mq : normalQueues) { + SelectableMessageQueue brokerActingQueue = new SelectableMessageQueue( + new MessageQueue(topic, mq.getMessageQueue().getBrokerName(), BROKER_ACTING_QUEUE_ID), + mq.getBrokerAddr()); + + if (!brokerActingQueues.contains(brokerActingQueue)) { + brokerActingQueues.add(brokerActingQueue); + brokerNameQueueMap.put(brokerActingQueue.getBrokerName(), brokerActingQueue); + } + } + + Collections.sort(brokerActingQueues); + } + + public final SelectableMessageQueue getQueueByBrokerName(String brokerName) { + return this.brokerNameQueueMap.get(brokerName); + } + + public final SelectableMessageQueue selectOne(boolean onlyBroker) { + int nextIndex = onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(); + return selectOneByIndex(nextIndex, onlyBroker); + } + + public final SelectableMessageQueue selectOne(String brokerName, int queueId) { + for (SelectableMessageQueue addressableMessageQueue : queues) { + String queueBrokerName = addressableMessageQueue.getBrokerName(); + if (queueBrokerName.equals(brokerName) && addressableMessageQueue.getQueueId() == queueId) { + return addressableMessageQueue; + } + } + return null; + } + + public final SelectableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { + if (onlyBroker) { + if (brokerActingQueues.isEmpty()) { + return null; + } + return brokerActingQueues.get(Math.abs(index) % brokerActingQueues.size()); + } + + if (queues.isEmpty()) { + return null; + } + return queues.get(Math.abs(index) % queues.size()); + } + + // find next same type(but different) queue with last(normal queue or broker acting queue). + public final SelectableMessageQueue selectNextQueue(SelectableMessageQueue last) { + boolean onlyBroker = last.getQueueId() < 0; + SelectableMessageQueue newOne = last; + int count = onlyBroker ? brokerActingQueues.size() : queues.size(); + + for (int i = 0; i < count; i++) { + newOne = selectOne(onlyBroker); + if (!newOne.getBrokerName().equals(last.getBrokerName()) || newOne.getQueueId() != last.getQueueId()) { + break; + } + } + + return newOne; + } + + public List getQueues() { + return queues; + } + + public List getBrokerActingQueues() { + return brokerActingQueues; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MessageQueueSelector)) { + return false; + } + MessageQueueSelector queue = (MessageQueueSelector) o; + return Objects.equals(queues, queue.queues) && + Objects.equals(brokerActingQueues, queue.brokerActingQueues); + } + + @Override + public int hashCode() { + return Objects.hash(queues, brokerActingQueues); + } + + @Override + public String toString() { + return "SelectableMessageQueue{" + "queues=" + queues + + ", brokers=" + brokerActingQueues + + ", queueIndex=" + queueIndex + + ", brokerIndex=" + brokerIndex + + '}'; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java index d93eaab979..50bb80959d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/MessageQueueWrapper.java @@ -19,17 +19,17 @@ package org.apache.rocketmq.proxy.client.route; import org.apache.rocketmq.common.protocol.route.TopicRouteData; public class MessageQueueWrapper { - public static final MessageQueueWrapper EMPTY_CACHED_QUEUE = new MessageQueueWrapper("", new TopicRouteData()); + public static final MessageQueueWrapper WRAPPED_EMPTY_QUEUE = new MessageQueueWrapper("", new TopicRouteData()); - private final SelectableMessageQueue read; - private final SelectableMessageQueue write; + private final MessageQueueSelector readSelector; + private final MessageQueueSelector writeSelector; private final TopicRouteWrapper topicRouteWrapper; public MessageQueueWrapper(String topic, TopicRouteData topicRouteData) { this.topicRouteWrapper = new TopicRouteWrapper(topicRouteData, topic); - this.read = new SelectableMessageQueue(topicRouteWrapper, true); - this.write = new SelectableMessageQueue(topicRouteWrapper, false); + this.readSelector = new MessageQueueSelector(topicRouteWrapper, true); + this.writeSelector = new MessageQueueSelector(topicRouteWrapper, false); } public TopicRouteData getTopicRouteData() { @@ -41,22 +41,22 @@ public class MessageQueueWrapper { } public boolean isEmptyCachedQueue() { - return this == EMPTY_CACHED_QUEUE; + return this == WRAPPED_EMPTY_QUEUE; } - public SelectableMessageQueue getRead() { - return read; + public MessageQueueSelector getReadSelector() { + return readSelector; } - public SelectableMessageQueue getWrite() { - return write; + public MessageQueueSelector getWriteSelector() { + return writeSelector; } @Override public String toString() { return "MessageQueueWrapper{" + - "read=" + read + - ", write=" + write + + "readSelector=" + readSelector + + ", writeSelector=" + writeSelector + ", topicRouteWrapper=" + topicRouteWrapper + '}'; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java index 88f7b3cee8..7f3f47adfa 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/SelectableMessageQueue.java @@ -16,188 +16,22 @@ */ package org.apache.rocketmq.proxy.client.route; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.route.QueueData; -public class SelectableMessageQueue { - private static final int BROKER_ACTING_QUEUE_ID = -1; +public class SelectableMessageQueue implements Comparable { - // multiple queues for one broker, with queueId : normal - private final List queues = new ArrayList<>(); - // one queue for one broker, with queueId : -1 - private final List brokerActingQueues = new ArrayList<>(); - private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); - private final AtomicInteger queueIndex; - private final AtomicInteger brokerIndex; + private final MessageQueue messageQueue; + private final String brokerAddr; - public SelectableMessageQueue(TopicRouteWrapper topicRouteWrapper, boolean read) { - if (read) { - this.queues.addAll(buildRead(topicRouteWrapper)); - } else { - this.queues.addAll(buildWrite(topicRouteWrapper)); - } - buildBrokerActingQueues(topicRouteWrapper.getTopicName(), this.queues); - - this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); - this.brokerIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + public SelectableMessageQueue(MessageQueue messageQueue, String brokerAddr) { + this.messageQueue = messageQueue; + this.brokerAddr = brokerAddr; } - private static List buildRead(TopicRouteWrapper topicRoute) { - Set queueSet = new HashSet<>(); - List qds = topicRoute.getQueueDatas(); - if (qds == null) { - return new ArrayList<>(); - } - - for (QueueData qd : qds) { - if (PermName.isReadable(qd.getPerm())) { - String brokerAddr = topicRoute.getMasterAddrPrefer(qd.getBrokerName()); - if (brokerAddr == null) { - continue; - } - - for (int i = 0; i < qd.getReadQueueNums(); i++) { - AddressableMessageQueue mq = new AddressableMessageQueue( - new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), - brokerAddr); - queueSet.add(mq); - } - } - } - - return queueSet.stream().sorted().collect(Collectors.toList()); - } - - private static List buildWrite(TopicRouteWrapper topicRoute) { - Set queueSet = new HashSet<>(); - // order topic route. - if (StringUtils.isNotBlank(topicRoute.getOrderTopicConf())) { - String[] brokers = topicRoute.getOrderTopicConf().split(";"); - for (String broker : brokers) { - String[] item = broker.split(":"); - String brokerName = item[0]; - String brokerAddr = topicRoute.getMasterAddr(brokerName); - if (brokerAddr == null) { - continue; - } - - int nums = Integer.parseInt(item[1]); - for (int i = 0; i < nums; i++) { - AddressableMessageQueue mq = new AddressableMessageQueue( - new MessageQueue(topicRoute.getTopicName(), brokerName, i), - brokerAddr); - queueSet.add(mq); - } - } - } else { - List qds = topicRoute.getQueueDatas(); - if (qds == null) { - return new ArrayList<>(); - } - - for (QueueData qd : qds) { - if (PermName.isWriteable(qd.getPerm())) { - String brokerAddr = topicRoute.getMasterAddr(qd.getBrokerName()); - if (brokerAddr == null) { - continue; - } - - for (int i = 0; i < qd.getWriteQueueNums(); i++) { - AddressableMessageQueue mq = new AddressableMessageQueue( - new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), - brokerAddr); - queueSet.add(mq); - } - } - } - } - - return queueSet.stream().sorted().collect(Collectors.toList()); - } - - private void buildBrokerActingQueues(String topic, List normalQueues) { - for (AddressableMessageQueue mq : normalQueues) { - AddressableMessageQueue brokerActingQueue = new AddressableMessageQueue( - new MessageQueue(topic, mq.getMessageQueue().getBrokerName(), BROKER_ACTING_QUEUE_ID), - mq.getBrokerAddr()); - - if (!brokerActingQueues.contains(brokerActingQueue)) { - brokerActingQueues.add(brokerActingQueue); - brokerNameQueueMap.put(brokerActingQueue.getBrokerName(), brokerActingQueue); - } - } - - Collections.sort(brokerActingQueues); - } - - public final AddressableMessageQueue getQueueByBrokerName(String brokerName) { - return this.brokerNameQueueMap.get(brokerName); - } - - public final AddressableMessageQueue selectOne(boolean onlyBroker) { - int nextIndex = onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(); - return selectOneByIndex(nextIndex, onlyBroker); - } - - public final AddressableMessageQueue selectOne(String brokerName, int queueId) { - for (AddressableMessageQueue addressableMessageQueue : queues) { - String queueBrokerName = addressableMessageQueue.getBrokerName(); - if (queueBrokerName.equals(brokerName) && addressableMessageQueue.getQueueId() == queueId) { - return addressableMessageQueue; - } - } - return null; - } - - public final AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { - if (onlyBroker) { - if (brokerActingQueues.isEmpty()) { - return null; - } - return brokerActingQueues.get(Math.abs(index) % brokerActingQueues.size()); - } - - if (queues.isEmpty()) { - return null; - } - return queues.get(Math.abs(index) % queues.size()); - } - - // find next same type(but different) queue with last(normal queue or broker acting queue). - public final AddressableMessageQueue selectNextQueue(AddressableMessageQueue last) { - boolean onlyBroker = last.getQueueId() < 0; - AddressableMessageQueue newOne = last; - int count = onlyBroker ? brokerActingQueues.size() : queues.size(); - - for (int i = 0; i < count; i++) { - newOne = selectOne(onlyBroker); - if (!newOne.getBrokerName().equals(last.getBrokerName()) || newOne.getQueueId() != last.getQueueId()) { - break; - } - } - - return newOne; - } - - public List getQueues() { - return queues; - } - - public List getBrokerActingQueues() { - return brokerActingQueues; + @Override + public int compareTo(SelectableMessageQueue o) { + return messageQueue.compareTo(o.messageQueue); } @Override @@ -209,21 +43,38 @@ public class SelectableMessageQueue { return false; } SelectableMessageQueue queue = (SelectableMessageQueue) o; - return Objects.equals(queues, queue.queues) && - Objects.equals(brokerActingQueues, queue.brokerActingQueues); + return Objects.equals(messageQueue, queue.messageQueue); } @Override public int hashCode() { - return Objects.hash(queues, brokerActingQueues); + return messageQueue == null ? 1 : messageQueue.hashCode(); } - @Override - public String toString() { - return "SelectableMessageQueue{" + "queues=" + queues + - ", brokers=" + brokerActingQueues + - ", queueIndex=" + queueIndex + - ", brokerIndex=" + brokerIndex + + public int getQueueId() { + return this.messageQueue.getQueueId(); + } + + public String getBrokerName() { + return this.messageQueue.getBrokerName(); + } + + public String getTopic() { + return messageQueue.getTopic(); + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + public String getBrokerAddr() { + return brokerAddr; + } + + @Override public String toString() { + return "AddressableMessageQueue{" + + "messageQueue=" + messageQueue + + ", brokerAddr='" + brokerAddr + '\'' + '}'; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java index 3c5b06de72..05da6904cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java @@ -176,8 +176,15 @@ public class TransactionId { this.gatewayTransactionId = gatewayTransactionId; } + @Override public String toString() { - return "TransactionId(brokerAddr=" + this.getBrokerAddr() + ", brokerTransactionId=" + this.getBrokerTransactionId() + ", commitLogOffset=" + this.getCommitLogOffset() + ", tranStateTableOffset=" + this.getTranStateTableOffset() + ", gatewayTransactionId=" + this.getGatewayTransactionId() + ")"; + return "TransactionId{" + + "brokerAddr=" + brokerAddr + + ", brokerTransactionId='" + brokerTransactionId + '\'' + + ", commitLogOffset=" + commitLogOffset + + ", tranStateTableOffset=" + tranStateTableOffset + + ", gatewayTransactionId='" + gatewayTransactionId + '\'' + + '}'; } public static class TransactionIdBuilder { @@ -219,8 +226,15 @@ public class TransactionId { return new TransactionId(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, gatewayTransactionId); } + @Override public String toString() { - return "TransactionId.TransactionIdBuilder(brokerAddr=" + this.brokerAddr + ", brokerTransactionId=" + this.brokerTransactionId + ", commitLogOffset=" + this.commitLogOffset + ", tranStateTableOffset=" + this.tranStateTableOffset + ", gatewayTransactionId=" + this.gatewayTransactionId + ")"; + return "TransactionId.TransactionIdBuilder{" + + "brokerAddr=" + brokerAddr + + ", brokerTransactionId='" + brokerTransactionId + '\'' + + ", commitLogOffset=" + commitLogOffset + + ", tranStateTableOffset=" + tranStateTableOffset + + ", gatewayTransactionId='" + gatewayTransactionId + '\'' + + '}'; } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java index 246ddde201..73cab80586 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java @@ -26,8 +26,14 @@ public class TransactionStateCheckRequest { private TransactionId transactionId; private MessageExt messageExt; - public TransactionStateCheckRequest(String groupId, Long tranStateTableOffset, Long commitLogOffset, - String msgId, TransactionId transactionId, MessageExt messageExt) { + public TransactionStateCheckRequest( + String groupId, + Long tranStateTableOffset, + Long commitLogOffset, + String msgId, + TransactionId transactionId, + MessageExt messageExt + ) { this.groupId = groupId; this.tranStateTableOffset = tranStateTableOffset; this.commitLogOffset = commitLogOffset; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java index bfbb0e7c43..6cea826cb2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java @@ -17,6 +17,5 @@ package org.apache.rocketmq.proxy.client.transaction; public interface TransactionStateChecker { - void checkTransactionState(TransactionStateCheckRequest checkData); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java index e69d31ae4c..56337eac8f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -32,7 +32,7 @@ public class ProxyConfig { * configuration for ThreadPoolMonitor */ private boolean enablePrintJstack = true; - private long printJstackPeriodMillis = 60000; + private long printJstackInMillis = 60000; private String nameSrvAddr = "11.165.223.199:9876"; private String nameSrvDomain = ""; @@ -56,16 +56,16 @@ public class ProxyConfig { */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; - private int expiredChannelTimeSec = 120; + private int channelExpiredInSeconds = 120; - private int consumerClientNum = 2; - private double consumerClientWorkerFactor = 0.2f; - private int producerClientNum = 2; - private double producerClientWorkerFactor = 0.2f; - private int defaultClientNum = 2; - private double defaultClientWorkerFactor = 0.2f; + private int forwardConsumerNum = 2; + private double forwardConsumerWorkerFactor = 0.2f; + private int forwardProducerNum = 2; + private double forwardProducerWorkerFactor = 0.2f; + private int defaultForwardClientNum = 2; + private double defaultForwardClientWorkerFactor = 0.2f; - private int topicRouteCacheExpireSecond = 20; + private int topicRouteCacheExpiredInSeconds = 20; private int topicRouteCacheExecutorThreadNum = 3; private int topicRouteCacheExecutorQueueCapacity = 1000; private int topicRouteCacheMaxNum = 20000; @@ -96,12 +96,12 @@ public class ProxyConfig { this.enablePrintJstack = enablePrintJstack; } - public long getPrintJstackPeriodMillis() { - return printJstackPeriodMillis; + public long getPrintJstackInMillis() { + return printJstackInMillis; } - public void setPrintJstackPeriodMillis(long printJstackPeriodMillis) { - this.printJstackPeriodMillis = printJstackPeriodMillis; + public void setPrintJstackInMillis(long printJstackInMillis) { + this.printJstackInMillis = printJstackInMillis; } public String getNameSrvAddr() { @@ -216,68 +216,68 @@ public class ProxyConfig { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } - public int getExpiredChannelTimeSec() { - return expiredChannelTimeSec; + public int getChannelExpiredInSeconds() { + return channelExpiredInSeconds; } - public void setExpiredChannelTimeSec(int expiredChannelTimeSec) { - this.expiredChannelTimeSec = expiredChannelTimeSec; + public void setChannelExpiredInSeconds(int channelExpiredInSeconds) { + this.channelExpiredInSeconds = channelExpiredInSeconds; } - public int getConsumerClientNum() { - return consumerClientNum; + public int getForwardConsumerNum() { + return forwardConsumerNum; } - public void setConsumerClientNum(int consumerClientNum) { - this.consumerClientNum = consumerClientNum; + public void setForwardConsumerNum(int forwardConsumerNum) { + this.forwardConsumerNum = forwardConsumerNum; } - public double getConsumerClientWorkerFactor() { - return consumerClientWorkerFactor; + public double getForwardConsumerWorkerFactor() { + return forwardConsumerWorkerFactor; } - public void setConsumerClientWorkerFactor(double consumerClientWorkerFactor) { - this.consumerClientWorkerFactor = consumerClientWorkerFactor; + public void setForwardConsumerWorkerFactor(double forwardConsumerWorkerFactor) { + this.forwardConsumerWorkerFactor = forwardConsumerWorkerFactor; } - public int getProducerClientNum() { - return producerClientNum; + public int getForwardProducerNum() { + return forwardProducerNum; } - public void setProducerClientNum(int producerClientNum) { - this.producerClientNum = producerClientNum; + public void setForwardProducerNum(int forwardProducerNum) { + this.forwardProducerNum = forwardProducerNum; } - public double getProducerClientWorkerFactor() { - return producerClientWorkerFactor; + public double getForwardProducerWorkerFactor() { + return forwardProducerWorkerFactor; } - public void setProducerClientWorkerFactor(double producerClientWorkerFactor) { - this.producerClientWorkerFactor = producerClientWorkerFactor; + public void setForwardProducerWorkerFactor(double forwardProducerWorkerFactor) { + this.forwardProducerWorkerFactor = forwardProducerWorkerFactor; } - public int getDefaultClientNum() { - return defaultClientNum; + public int getDefaultForwardClientNum() { + return defaultForwardClientNum; } - public void setDefaultClientNum(int defaultClientNum) { - this.defaultClientNum = defaultClientNum; + public void setDefaultForwardClientNum(int defaultForwardClientNum) { + this.defaultForwardClientNum = defaultForwardClientNum; } - public double getDefaultClientWorkerFactor() { - return defaultClientWorkerFactor; + public double getDefaultForwardClientWorkerFactor() { + return defaultForwardClientWorkerFactor; } - public void setDefaultClientWorkerFactor(double defaultClientWorkerFactor) { - this.defaultClientWorkerFactor = defaultClientWorkerFactor; + public void setDefaultForwardClientWorkerFactor(double defaultForwardClientWorkerFactor) { + this.defaultForwardClientWorkerFactor = defaultForwardClientWorkerFactor; } - public int getTopicRouteCacheExpireSecond() { - return topicRouteCacheExpireSecond; + public int getTopicRouteCacheExpiredInSeconds() { + return topicRouteCacheExpiredInSeconds; } - public void setTopicRouteCacheExpireSecond(int topicRouteCacheExpireSecond) { - this.topicRouteCacheExpireSecond = topicRouteCacheExpireSecond; + public void setTopicRouteCacheExpiredInSeconds(int topicRouteCacheExpiredInSeconds) { + this.topicRouteCacheExpiredInSeconds = topicRouteCacheExpiredInSeconds; } public int getTopicRouteCacheExecutorThreadNum() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 798a918523..a7d1404eda 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -54,7 +54,7 @@ import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.ForwardClientManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; @@ -64,12 +64,12 @@ import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ClientManager clientManager; + private final ForwardClientManager clientManager; private final ProducerService producerService; private final RouteService routeService; public ClusterGrpcService() { - this.clientManager = new ClientManager(checkData -> { + this.clientManager = new ForwardClientManager(checkData -> { }); this.producerService = new ProducerService(clientManager); this.routeService = new RouteService(clientManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index acb9691322..b9837ef2a1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -16,13 +16,13 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.ForwardClientManager; public class BaseService { - protected final ClientManager clientManager; + protected final ForwardClientManager clientManager; - public BaseService(ClientManager clientManager) { + public BaseService(ForwardClientManager clientManager) { this.clientManager = clientManager; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 7aa6887443..cc898d16ab 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -20,11 +20,11 @@ import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.proxy.client.ClientManager; +import org.apache.rocketmq.proxy.client.ForwardClientManager; public class ConsumerService extends BaseService { - public ConsumerService(ClientManager clientManager) { + public ConsumerService(ForwardClientManager clientManager) { super(clientManager); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 94c316778d..8cabdf0204 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -25,8 +25,8 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.client.ClientManager; -import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; @@ -42,19 +42,19 @@ public class ProducerService extends BaseService { private volatile ProducerServiceHook producerServiceHook = null; private volatile MessageQueueSelector messageQueueSelector = new DefaultMessageQueueSelector(); - public ProducerService(ClientManager clientManager) { + public ProducerService(ForwardClientManager clientManager) { super(clientManager); } public interface MessageQueueSelector { - AddressableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, + SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, org.apache.rocketmq.common.message.Message message); } public class DefaultMessageQueueSelector implements MessageQueueSelector { @Override - public AddressableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, + public SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, org.apache.rocketmq.common.message.Message message) { try { String topic = requestHeader.getTopic(); @@ -64,7 +64,7 @@ public class ProducerService extends BaseService { } Integer queueId = requestHeader.getQueueId(); String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); - AddressableMessageQueue addressableMessageQueue; + SelectableMessageQueue addressableMessageQueue; if (!StringUtils.isBlank(brokerName) && queueId != null) { // Grpc client sendSelect situation addressableMessageQueue = selectTargetQueue(topic, brokerName, queueId); @@ -81,24 +81,24 @@ public class ProducerService extends BaseService { } } - protected AddressableMessageQueue selectNormalQueue(String topic) throws Exception { + protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, null); } - protected AddressableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { + protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, brokerName, queueId); } - protected AddressableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { + protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { return clientManager.getTopicRouteCache().selectOneWriteQueueByKey(topic, shardingKey, null); } } public interface ProducerServiceHook { - void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader); + void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader); - void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader, + void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader, SendResult sendResult); } @@ -116,7 +116,7 @@ public class ProducerService extends BaseService { try { SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); - AddressableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); + SelectableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); if (addressableMessageQueue == null) { @@ -127,7 +127,7 @@ public class ProducerService extends BaseService { if (producerServiceHook != null) { producerServiceHook.beforeSend(ctx, addressableMessageQueue, message, requestHeader); } - CompletableFuture sendResultCompletableFuture = this.clientManager.getProducerClient().sendMessage( + CompletableFuture sendResultCompletableFuture = this.clientManager.getForwardProducer().sendMessage( addressableMessageQueue.getBrokerAddr(), addressableMessageQueue.getBrokerName(), message, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 6bb10534bc..3809e8073e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -34,8 +34,8 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.client.ClientManager; -import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.common.RocketMQHelper; import org.apache.rocketmq.proxy.grpc.common.Converter; @@ -47,7 +47,7 @@ public class RouteService extends BaseService { private volatile QueryRouteHook queryRouteHook = null; private volatile QueryAssignmentHook queryAssignmentHook = null; - public RouteService(ClientManager clientManager) { + public RouteService(ForwardClientManager clientManager) { super(clientManager); } @@ -61,16 +61,16 @@ public class RouteService extends BaseService { } public interface RouteAssignmentQueueSelector { - List getAssignment(QueryAssignmentRequest request) throws Exception; + List getAssignment(QueryAssignmentRequest request) throws Exception; } public class DefaultRouteAssignmentQueueSelector implements RouteAssignmentQueueSelector { @Override - public List getAssignment(QueryAssignmentRequest request) throws Exception { + public List getAssignment(QueryAssignmentRequest request) throws Exception { MessageQueueWrapper messageQueueWrapper = clientManager.getTopicRouteCache() .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); - return messageQueueWrapper.getRead().getBrokerActingQueues(); + return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); } } @@ -189,9 +189,9 @@ public class RouteService extends BaseService { } List assignments = new ArrayList<>(); - List messageQueueList = this.assignmentQueueSelector.getAssignment(request); + List messageQueueList = this.assignmentQueueSelector.getAssignment(request); - for (AddressableMessageQueue messageQueue : messageQueueList) { + for (SelectableMessageQueue messageQueue : messageQueueList) { Broker broker = Broker.newBuilder() .setName(messageQueue.getBrokerName()) .setId(0) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java index 9a5703aa36..d3121f32e5 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java @@ -30,20 +30,20 @@ public class ClientManagerTest extends InitConfigurationTest { @Test public void testClientManager() throws Exception { TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); - ClientManager clientManager = new ClientManager(mockedTransactionStateChecker); + ForwardClientManager clientManager = new ForwardClientManager(mockedTransactionStateChecker); clientManager.start(); - assertThat(clientManager.getDefaultClient()).isNotNull(); - assertThat(clientManager.getDefaultClient().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultClientNum()); + assertThat(clientManager.getDefaultForwardClient()).isNotNull(); + assertThat(clientManager.getDefaultForwardClient().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultForwardClientNum()); - assertThat(clientManager.getProducerClient()).isNotNull(); - assertThat(clientManager.getProducerClient().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getProducerClientNum()); + assertThat(clientManager.getForwardProducer()).isNotNull(); + assertThat(clientManager.getForwardProducer().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getForwardProducerNum()); - assertThat(clientManager.getReadConsumerClient()).isNotNull(); - assertThat(clientManager.getReadConsumerClient().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getConsumerClientNum()); + assertThat(clientManager.getForwardReadConsumer()).isNotNull(); + assertThat(clientManager.getForwardReadConsumer().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java index fd220378a0..9a6ab623ae 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java @@ -16,12 +16,12 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import org.apache.rocketmq.proxy.client.ClientManager; -import org.apache.rocketmq.proxy.client.DefaultClient; -import org.apache.rocketmq.proxy.client.ProducerClient; -import org.apache.rocketmq.proxy.client.ReadConsumerClient; +import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.client.DefaultForwardClient; +import org.apache.rocketmq.proxy.client.ForwardProducer; +import org.apache.rocketmq.proxy.client.ForwardReadConsumer; import org.apache.rocketmq.proxy.client.TopicRouteCache; -import org.apache.rocketmq.proxy.client.WriteConsumerClient; +import org.apache.rocketmq.proxy.client.ForwardWriteConsumer; import org.junit.Before; import org.junit.Ignore; import org.junit.runner.RunWith; @@ -35,24 +35,24 @@ import static org.mockito.Mockito.when; public abstract class BaseServiceTest { @Mock - protected ClientManager clientManager; + protected ForwardClientManager clientManager; @Mock - protected DefaultClient defaultClient; + protected DefaultForwardClient defaultClient; @Mock - protected ProducerClient producerClient; + protected ForwardProducer producerClient; @Mock - protected ReadConsumerClient readConsumerClient; + protected ForwardReadConsumer readConsumerClient; @Mock - protected WriteConsumerClient writeConsumerClient; + protected ForwardWriteConsumer writeConsumerClient; @Mock protected TopicRouteCache topicRouteCache; @Before public void before() throws Throwable { - when(clientManager.getDefaultClient()).thenReturn(defaultClient); - when(clientManager.getProducerClient()).thenReturn(producerClient); - when(clientManager.getReadConsumerClient()).thenReturn(readConsumerClient); - when(clientManager.getWriteConsumerClient()).thenReturn(writeConsumerClient); + when(clientManager.getDefaultForwardClient()).thenReturn(defaultClient); + when(clientManager.getForwardProducer()).thenReturn(producerClient); + when(clientManager.getForwardReadConsumer()).thenReturn(readConsumerClient); + when(clientManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); when(clientManager.getTopicRouteCache()).thenReturn(topicRouteCache); beforeEach(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 4165ad8d69..2ec8bb4602 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -35,7 +35,7 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.client.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; import org.junit.Test; @@ -56,19 +56,19 @@ public class ProducerServiceTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { - AddressableMessageQueue queue = new AddressableMessageQueue( + SelectableMessageQueue queue = new SelectableMessageQueue( new MessageQueue("topic", "selectOrderQueue", 0), "selectOrderQueueAddr"); when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString(), isNull())) .thenReturn(queue); - queue = new AddressableMessageQueue( + queue = new SelectableMessageQueue( new MessageQueue("topic", "selectTargetQueue", 0), "selectTargetQueueAddr"); when(topicRouteCache.selectOneWriteQueue(anyString(), anyString(), anyInt())) .thenReturn(queue); - queue = new AddressableMessageQueue( + queue = new SelectableMessageQueue( new MessageQueue("topic", "selectNormalQueue", 0), "selectNormalQueueAddr"); when(topicRouteCache.selectOneWriteQueue(anyString(), isNull())) @@ -85,17 +85,17 @@ public class ProducerServiceTest extends BaseServiceTest { ProducerService producerService = new ProducerService(this.clientManager); - AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference selectQueueRef = new AtomicReference<>(); AtomicReference messageRef = new AtomicReference<>(); producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { @Override - public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { selectQueueRef.set(addressableMessageQueue); } @Override - public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, SendResult sendResult) { @@ -138,17 +138,17 @@ public class ProducerServiceTest extends BaseServiceTest { ProducerService producerService = new ProducerService(this.clientManager); - AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference selectQueueRef = new AtomicReference<>(); AtomicReference messageRef = new AtomicReference<>(); producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { @Override - public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { selectQueueRef.set(addressableMessageQueue); } @Override - public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, SendResult sendResult) { @@ -190,17 +190,17 @@ public class ProducerServiceTest extends BaseServiceTest { ProducerService producerService = new ProducerService(this.clientManager); - AtomicReference selectQueueRef = new AtomicReference<>(); + AtomicReference selectQueueRef = new AtomicReference<>(); AtomicReference messageRef = new AtomicReference<>(); producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { @Override - public void beforeSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { selectQueueRef.set(addressableMessageQueue); } @Override - public void afterSend(Context ctx, AddressableMessageQueue addressableMessageQueue, + public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, SendResult sendResult) { From 6b985f766a408186206b01dd8fd31bd7d0a7cb32 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 15:11:45 +0800 Subject: [PATCH 025/338] [ISSUE #3949] Fix unit test --- .../rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index a16bf2cc42..6fb45c3fc3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -27,11 +27,13 @@ import com.google.rpc.Code; import io.grpc.Context; import io.grpc.Metadata; import io.netty.channel.ChannelHandlerContext; +import java.net.URL; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.processor.ClientManageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -43,6 +45,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; @RunWith(MockitoJUnitRunner.class) From 60868dafc93192a59a9bdc9ff62be8319f6b4909 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 17:00:50 +0800 Subject: [PATCH 026/338] [ISSUE #3949] Add receiveMessage --- common/pom.xml | 4 + .../rocketmq/common/utils/BinaryUtil.java | 46 +++++ pom.xml | 2 +- .../proxy/configuration/ProxyConfig.java | 13 ++ .../channel/ReceiveMessageChannel.java | 52 ++++++ .../ReceiveMessageResponseHandler.java | 146 +++++++++++++++ .../rocketmq/proxy/grpc/common/Converter.java | 168 ++++++++++++++++++ .../proxy/grpc/service/LocalGrpcService.java | 35 +++- .../grpc/service/LocalGrpcServiceTest.java | 71 +++++++- 9 files changed, 529 insertions(+), 8 deletions(-) create mode 100644 common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java diff --git a/common/pom.xml b/common/pom.xml index ad2046a28f..feedeabad2 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -49,5 +49,9 @@ slf4j-api 1.7.7 + + commons-codec + commons-codec + 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 new file mode 100644 index 0000000000..421adaca4d --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/utils/BinaryUtil.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.common.utils; + +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import org.apache.commons.codec.binary.Hex; + +public class BinaryUtil { + public static byte[] calculateMd5(byte[] binaryData) { + MessageDigest messageDigest = null; + try { + messageDigest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 algorithm not found."); + } + messageDigest.update(binaryData); + return messageDigest.digest(); + } + + public static String generateMd5(String bodyStr) { + byte[] bytes = calculateMd5(bodyStr.getBytes(Charset.forName("UTF-8"))); + return Hex.encodeHexString(bytes, false); + } + + public static String generateMd5(byte[] content) { + byte[] bytes = calculateMd5(content); + return Hex.encodeHexString(bytes, false); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 851600fd10..6022764122 100644 --- a/pom.xml +++ b/pom.xml @@ -611,7 +611,7 @@ commons-codec commons-codec - 1.9 + 1.13 org.apache.logging.log4j diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java index 56337eac8f..a3aff93c19 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.configuration; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; public class ProxyConfig { @@ -228,6 +229,18 @@ public class ProxyConfig { return forwardConsumerNum; } + public long getLongPollingReserveTimeMill() { + return longPollingReserveTimeMill; + } + + public void setLongPollingReserveTimeMill(long longPollingReserveTimeMill) { + this.longPollingReserveTimeMill = longPollingReserveTimeMill; + } + + public int getConsumerClientNum() { + return consumerClientNum; + } + public void setForwardConsumerNum(int forwardConsumerNum) { this.forwardConsumerNum = forwardConsumerNum; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java new file mode 100644 index 0000000000..6319d7d2d8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.channel; + +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import io.netty.channel.ChannelFuture; +import org.apache.rocketmq.proxy.channel.InvocationChannel; +import org.apache.rocketmq.proxy.channel.SimpleChannel; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ReceiveMessageChannel extends InvocationChannel { + private final ReceiveMessageResponseHandler handler; + + public static ReceiveMessageChannel create(SimpleChannel other, ReceiveMessageResponseHandler handler) { + return new ReceiveMessageChannel(other, handler); + } + + private ReceiveMessageChannel(SimpleChannel simpleChannel, ReceiveMessageResponseHandler handler) { + super(simpleChannel); + this.handler = handler; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + if (msg instanceof RemotingCommand) { + RemotingCommand responseCommand = (RemotingCommand) msg; + InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); + if (null != context) { + handler.handle(responseCommand, context); + } + } + return super.writeAndFlush(msg); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java new file mode 100644 index 0000000000..f85cf4cc41 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java @@ -0,0 +1,146 @@ +/* + * 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.grpc.adapter.handler; + +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.Resource; +import com.google.common.base.Stopwatch; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReceiveMessageResponseHandler implements ResponseHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + @Override public void handle(RemotingCommand responseCommand, + InvocationContext context) { + ReceiveMessageRequest request = context.getRequest(); + CompletableFuture future = context.getResponse(); + + String brokerName = request.getPartition().getBroker().getName(); + long currentTimeInMillis = System.currentTimeMillis(); + long popCosts = currentTimeInMillis - context.getTimestamp(); + try { + Stopwatch stopWatch = Stopwatch.createStarted(); + ReceiveMessageResponse.Builder builder = ReceiveMessageResponse.newBuilder(); + PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) responseCommand.readCustomHeader(); + builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + builder.setInvisibleDuration(Durations.fromMillis(responseHeader.getInvisibleTime())) + .setDeliveryTimestamp(Timestamps.fromMillis(responseHeader.getPopTime())); + + ReceiveMessageResponse response; + if (responseCommand.getCode() == RemotingSysResponseCode.SUCCESS) { + ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); + List msgFoundList = MessageDecoder.decodes(byteBuffer); + + Map startOffsetInfo; + Map> msgOffsetInfo; + Map orderCountInfo; + startOffsetInfo = ExtraInfoUtil.parseStartOffsetInfo(responseHeader.getStartOffsetInfo()); + msgOffsetInfo = ExtraInfoUtil.parseMsgOffsetInfo(responseHeader.getMsgOffsetInfo()); + orderCountInfo = ExtraInfoUtil.parseOrderCountInfo(responseHeader.getOrderCountInfo()); + Map/*msg queueOffset*/> sortMap = new HashMap<>(16); + for (MessageExt messageExt : msgFoundList) { + String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); + if (!sortMap.containsKey(key)) { + sortMap.put(key, new ArrayList<>(4)); + } + sortMap.get(key).add(messageExt.getQueueOffset()); + } + Map map = new HashMap<>(5); + for (MessageExt messageExt : msgFoundList) { + if (startOffsetInfo == null) { + // we should set the check point info to extraInfo field , if the command is popMsg + // find pop ck offset + String key = messageExt.getTopic() + messageExt.getQueueId(); + if (!map.containsKey(messageExt.getTopic() + messageExt.getQueueId())) { + String extraInfo = ExtraInfoUtil.buildExtraInfo(messageExt.getQueueOffset(), + responseHeader.getPopTime(), responseHeader.getInvisibleTime(), + responseHeader.getReviveQid(), messageExt.getTopic(), brokerName, + messageExt.getQueueId()); + map.put(key, extraInfo); + } + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, + map.get(key) + MessageConst.KEY_SEPARATOR + messageExt.getQueueOffset()); + } else { + String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), + messageExt.getQueueId()); + int index = sortMap.get(key).indexOf(messageExt.getQueueOffset()); + Long msgQueueOffset = msgOffsetInfo.get(key).get(index); + if (msgQueueOffset != messageExt.getQueueOffset()) { + LOGGER.warn("Queue offset[{}] of msg is strange, not equal to the stored in msg, {}", + msgQueueOffset, messageExt); + } + String extraInfo = ExtraInfoUtil.buildExtraInfo(startOffsetInfo.get(key), + responseHeader.getPopTime(), responseHeader.getInvisibleTime(), + responseHeader.getReviveQid(), messageExt.getTopic(), + brokerName, messageExt.getQueueId(), msgQueueOffset); + messageExt.setQueueOffset(msgQueueOffset); + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, extraInfo); + if (context.getRequest().getFifoFlag() && orderCountInfo != null) { + Integer count = orderCountInfo.get(key); + if (count != null && count > 0) { + messageExt.setReconsumeTimes(count); + } + } + } + Resource topic = context.getRequest() + .getPartition() + .getTopic(); + String topicName = Converter.getResourceNameWithNamespace(topic); + messageExt.setTopic(topicName); + messageExt.setBrokerName(brokerName); + messageExt.getProperties().computeIfAbsent(MessageConst.PROPERTY_FIRST_POP_TIME, + k -> String.valueOf(responseHeader.getPopTime())); + } + + for (MessageExt messageExt : msgFoundList) { + builder.addMessages(Converter.buildMessage(messageExt)); + } + } + response = builder.build(); + long elapsed = stopWatch.stop().elapsed(TimeUnit.MILLISECONDS); + LOGGER.debug("Translating remoting response to gRPC response costs {}ms. Duration request received: {}", + elapsed, popCosts); + future.complete(response); + } catch (Exception e) { + LOGGER.error("Unexpected exception raised when handle pop remoting command", e); + future.completeExceptionally(e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 5edadf45a4..c6ec938570 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -21,6 +21,8 @@ import apache.rocketmq.v1.ConsumeMessageType; import apache.rocketmq.v1.ConsumeModel; import apache.rocketmq.v1.ConsumePolicy; import apache.rocketmq.v1.ConsumerData; +import apache.rocketmq.v1.Digest; +import apache.rocketmq.v1.DigestType; import apache.rocketmq.v1.Encoding; import apache.rocketmq.v1.FilterExpression; import apache.rocketmq.v1.FilterType; @@ -35,14 +37,19 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SubscriptionEntry; import apache.rocketmq.v1.SystemAttribute; import com.google.common.collect.Maps; +import com.google.protobuf.ByteString; import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import java.net.SocketAddress; +import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; @@ -51,6 +58,7 @@ import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; @@ -59,6 +67,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.common.utils.BinaryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -320,4 +329,163 @@ public class Converter { return ConsumeInitMode.MAX; } } + + public static Message buildMessage(MessageExt messageExt) { + Map userAttributes = buildUserAttributes(messageExt); + SystemAttribute systemAttributes = buildSystemAttributes(messageExt); + Resource topic = Resource.newBuilder() + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) + .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) + .build(); + return Message.newBuilder() + .setTopic(topic) + .putAllUserAttribute(userAttributes) + .setSystemAttribute(systemAttributes) + .setBody(ByteString.copyFrom(messageExt.getBody())) + .build(); + } + + protected static Map buildUserAttributes(MessageExt messageExt) { + Map userAttributes = new HashMap<>(); + Map properties = messageExt.getProperties(); + + for (Map.Entry property : properties.entrySet()) { + if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { + userAttributes.put(property.getKey(), property.getValue()); + } + } + + return userAttributes; + } + + protected static SystemAttribute buildSystemAttributes(MessageExt messageExt) { + SystemAttribute.Builder systemAttributeBuilder = SystemAttribute.newBuilder(); + + // tag + String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); + if (tag != null) { + systemAttributeBuilder.setTag(tag); + } + + // keys + String keys = messageExt.getKeys(); + if (keys != null) { + String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); + systemAttributeBuilder.addAllKeys(Arrays.asList(keysArray)); + } + + // message_id + String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); + if (uniqKey != null) { + systemAttributeBuilder.setMessageId(uniqKey); + } + + // body_digest & body_encoding + String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); + Digest digest = Digest.newBuilder() + .setType(DigestType.MD5) + .setChecksum(md5Result) + .build(); + systemAttributeBuilder.setBodyDigest(digest); + + if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { + systemAttributeBuilder.setBodyEncoding(Encoding.GZIP); + } else { + systemAttributeBuilder.setBodyEncoding(Encoding.IDENTITY); + } + + // message_type + String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + String isTransValue = "true"; + if (isTransValue.equals(isTrans)) { + systemAttributeBuilder.setMessageType(MessageType.TRANSACTION); + } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + systemAttributeBuilder.setMessageType(MessageType.DELAY); + } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { + systemAttributeBuilder.setMessageType(MessageType.FIFO); + } else { + systemAttributeBuilder.setMessageType(MessageType.NORMAL); + } + + // born_timestamp (millis) + long bornTimestamp = messageExt.getBornTimestamp(); + systemAttributeBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); + + // born_host + systemAttributeBuilder.setBornHost(messageExt.getBornHostString()); + + // store_timestamp (millis) + long storeTimestamp = messageExt.getStoreTimestamp(); + systemAttributeBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); + + // store_host + SocketAddress storeHost = messageExt.getStoreHost(); + if (storeHost != null) { + systemAttributeBuilder.setStoreHost(storeHost.toString()); + } + + // delay_level + String delayLevel = messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL); + if (delayLevel != null) { + systemAttributeBuilder.setDelayLevel(Integer.parseInt(delayLevel)); + } + + // delivery_timestamp + String deliverMsString; + long deliverMs; + if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); + deliverMs = System.currentTimeMillis() + delayMs; + systemAttributeBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } else { + deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); + if (deliverMsString != null) { + deliverMs = Long.parseLong(deliverMsString); + systemAttributeBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } + } + + // sharding key + String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + if (shardingKey != null) { + systemAttributeBuilder.setMessageGroup(shardingKey); + } + + // receipt_handle && invisible_period + String ckInfo = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (ckInfo != null) { + systemAttributeBuilder.setReceiptHandle(ckInfo); + } + + // partition_id + systemAttributeBuilder.setPartitionId(messageExt.getQueueId()); + + // partition_offset + systemAttributeBuilder.setPartitionOffset(messageExt.getQueueOffset()); + + // delivery_attempt + systemAttributeBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); + + // publisher_group + String producerGroup = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); + if (producerGroup != null) { + String namespaceId = NamespaceUtil.getNamespaceFromResource(producerGroup); + String group = NamespaceUtil.withoutNamespace(producerGroup); + systemAttributeBuilder.setProducerGroup(Resource.newBuilder() + .setResourceNamespace(namespaceId) + .setName(group) + .build()); + } + + // trace context + String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); + if (traceContext != null) { + systemAttributeBuilder.setTraceContext(traceContext); + } + + return systemAttributeBuilder.build(); + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 4277c95a0e..b806ec6e7a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -63,13 +63,17 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; @@ -161,7 +165,36 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return null; + long timeRemaining = Context.current() + .getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeMill(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + PopMessageRequestHeader requestHeader = Converter.buildPopMessageRequestHeader(request, pollTime); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); + command.makeCustomHeaderToNet(); + + ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(); + ReceiveMessageChannel channel = ReceiveMessageChannel.create(channelManager.createChannel(), handler); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + CompletableFuture future = new CompletableFuture<>(); + InvocationContext context + = new InvocationContext<>(request, future); + channel.registerInvocationContext(command.getOpaque(), context); + try { + RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(channelHandlerContext, command); + if (response != null) { + handler.handle(response, context); + channel.eraseInvocationContext(command.getOpaque()); + } + } catch (Exception e) { + LOGGER.error("Failed to process pop message command", e); + channel.eraseInvocationContext(command.getOpaque()); + future.completeExceptionally(e); + } + return future; } @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 6fb45c3fc3..ccfbb34fa6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -20,21 +20,34 @@ package org.apache.rocketmq.proxy.grpc.service; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.util.Durations; import com.google.rpc.Code; import io.grpc.Context; import io.grpc.Metadata; import io.netty.channel.ChannelHandlerContext; +import java.net.InetSocketAddress; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.processor.ClientManageProcessor; +import org.apache.rocketmq.broker.processor.PopMessageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; +import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -54,6 +67,8 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { @Mock private SendMessageProcessor sendMessageProcessorMock; @Mock + private PopMessageProcessor popMessageProcessorMock; + @Mock private BrokerController brokerControllerMock; private Metadata metadata; @@ -71,6 +86,7 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { ConfigurationManager.initEnv(); ConfigurationManager.intConfig(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); localGrpcService = new LocalGrpcService(brokerControllerMock); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); @@ -133,9 +149,6 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { .build()) .build()) .build(); - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); @@ -153,9 +166,6 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { .build()) .build()) .build(); - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); @@ -164,4 +174,53 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { return null; }); } + + @Test + public void testReceiveMessageSuccess() throws Exception { + long invisibleTime = 1000L; + String topic = "topic"; + byte[] body = "123".getBytes(StandardCharsets.UTF_8); + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody(body); + messageExt.putUserProperty("key", "value"); + PopMessageResponseHeader responseHeader = new PopMessageResponseHeader(); + responseHeader.setInvisibleTime(invisibleTime); + RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(ResponseCode.SUCCESS, responseHeader); + remotingCommand.setBody(MessageDecoder.encode(messageExt, true)); + remotingCommand.makeCustomHeaderToNet(); + Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(remotingCommand); + ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder().getDefaultInstanceForType(); + CompletableFuture grpcFuture = localGrpcService.receiveMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("test"))) + .attach(), request); + grpcFuture.thenAccept(r -> { + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getMessagesCount()).isEqualTo(0); + assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); + assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); + assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); + }); + } + + @Test + public void testReceiveMessageSuccessWriteAndFlush() throws Exception { + Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(null); + ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder().getDefaultInstanceForType(); + CompletableFuture grpcFuture = localGrpcService.receiveMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("test"))) + .attach(), request); + grpcFuture.thenAccept(r -> assertThat(r).isNull()); + } } \ No newline at end of file From 0cd8ff08eeab5a0d4a32590a4a77863c8e9a6cc7 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 18:47:46 +0800 Subject: [PATCH 027/338] [ISSUE #3949] Remove consumerGroupInfo in PopMessageProcessor --- .../rocketmq/broker/processor/PopMessageProcessor.java | 9 --------- 1 file changed, 9 deletions(-) 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 333b20cecd..7708f415ea 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 @@ -33,7 +33,6 @@ import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.broker.client.ConsumerGroupInfo; import org.apache.rocketmq.broker.filter.ConsumerFilterData; import org.apache.rocketmq.broker.filter.ConsumerFilterManager; import org.apache.rocketmq.broker.filter.ExpressionMessageFilter; @@ -304,14 +303,6 @@ public class PopMessageProcessor implements NettyRequestProcessor { requestHeader.getConsumerGroup(), FAQUrl.suggestTodo(FAQUrl.SUBSCRIPTION_GROUP_NOT_EXIST))); return response; } - ConsumerGroupInfo consumerGroupInfo = - this.brokerController.getConsumerManager().getConsumerGroupInfo(requestHeader.getConsumerGroup()); - if (null == consumerGroupInfo) { - POP_LOGGER.warn("the consumer's group info not exist, group: {}", requestHeader.getConsumerGroup()); - response.setCode(ResponseCode.SUBSCRIPTION_NOT_EXIST); - response.setRemark("the consumer's group info not exist" + FAQUrl.suggestTodo(FAQUrl.SAME_GROUP_DIFFERENT_TOPIC)); - return response; - } if (!subscriptionGroupConfig.isConsumeEnable()) { response.setCode(ResponseCode.NO_PERMISSION); From 19161001f057a5a2e2a8b6e646923620f02086f6 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 15 Mar 2022 18:48:06 +0800 Subject: [PATCH 028/338] [ISSUE #3949] Add IT --- pom.xml | 7 +- proxy/pom.xml | 5 +- .../rocketmq/proxy/grpc/GrpcServer.java | 2 + .../grpc/interceptor/ContextInterceptor.java | 37 ++ .../grpc/service/LocalGrpcServiceTest.java | 2 - test/pom.xml | 13 + .../rocketmq/test/base/GrpcBaseTest.java | 78 ++++ .../rocketmq/test/proxy/LocalGrpcTest.java | 112 +++++ .../resources/rmq-proxy-home/conf/broker.conf | 22 + .../rmq-proxy-home/conf/logback_proxy.xml | 420 ++++++++++++++++++ .../rmq-proxy-home/conf/rmq-proxy.json | 3 + 11 files changed, 697 insertions(+), 4 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java create mode 100644 test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java create mode 100644 test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java create mode 100644 test/src/test/resources/rmq-proxy-home/conf/broker.conf create mode 100644 test/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml create mode 100644 test/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json diff --git a/pom.xml b/pom.xml index 6022764122..d5276af488 100644 --- a/pom.xml +++ b/pom.xml @@ -451,6 +451,11 @@ + + ${project.groupId} + rocketmq-proto + 5.0.0-SNAPSHOT + ${project.groupId} rocketmq-client @@ -528,7 +533,7 @@ ${project.groupId} - rocketmq-grpc + rocketmq-proxy ${project.version} diff --git a/proxy/pom.xml b/proxy/pom.xml index b38e097333..337e94c8c6 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -39,7 +39,10 @@ org.apache.rocketmq rocketmq-proto - 5.0.0-SNAPSHOT + + + org.apache.rocketmq + rocketmq-proxy org.apache.rocketmq 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 8ebec3d4b7..0c027f5377 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 @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.slf4j.Logger; @@ -91,6 +92,7 @@ public class GrpcServer { .channelType(NioServerSocketChannel.class) .addService(messagingProcessor) .executor(this.executor) + .intercept(new ContextInterceptor()) .intercept(new HeaderInterceptor()) .build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java new file mode 100644 index 0000000000..259f02d926 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.interceptor; + +import io.grpc.Context; +import io.grpc.Contexts; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; + +public class ContextInterceptor implements ServerInterceptor { + + @Override + public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, + ServerCallHandler next) { + Context context = Context.current() + .withValue(InterceptorConstants.METADATA, headers); + return Contexts.interceptCall(context, call, headers, next); + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index ccfbb34fa6..b78534a9fd 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -83,8 +83,6 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { System.setProperty(RMQ_PROXY_HOME, mockProxyHome); ConfigurationManager.initEnv(); ConfigurationManager.intConfig(); - ConfigurationManager.initEnv(); - ConfigurationManager.intConfig(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); localGrpcService = new LocalGrpcService(brokerControllerMock); diff --git a/test/pom.xml b/test/pom.xml index 3cf4f2d615..516e8fa7a7 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -32,6 +32,14 @@ log4j log4j + + ${project.groupId} + rocketmq-proto + + + ${project.groupId} + rocketmq-proxy + ${project.groupId} rocketmq-broker @@ -69,6 +77,11 @@ ${project.groupId} rocketmq-tools + + io.grpc + grpc-testing + test + diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java new file mode 100644 index 0000000000..25729bf16e --- /dev/null +++ b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.test.base; + +import io.grpc.Channel; +import io.grpc.ServerInterceptors; +import io.grpc.ServerServiceDefinition; +import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; +import io.grpc.testing.GrpcCleanupRule; +import io.netty.handler.ssl.ApplicationProtocolNames; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.handler.ssl.util.SelfSignedCertificate; +import java.io.IOException; +import java.security.cert.CertificateException; +import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; +import org.junit.Rule; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class GrpcBaseTest extends BaseConf { + /** + * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. + */ + @Rule + public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + protected Channel setUpServer(apache.rocketmq.v1.MessagingServiceGrpc.MessagingServiceImplBase serverImpl, + int port, boolean enableInterceptor) throws IOException, CertificateException { + SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(serverImpl); + if (enableInterceptor) { + serviceDefinition = ServerInterceptors.intercept(serverImpl, new ContextInterceptor(), new HeaderInterceptor()); + } + // Create a server, add service, start, and register for automatic graceful shutdown. + grpcCleanup.register(NettyServerBuilder.forPort(port) + .directExecutor() + .addService(serviceDefinition) + .useTransportSecurity(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .build() + .start()); + // Create a client channel and register for automatic graceful shutdown. + return grpcCleanup.register(NettyChannelBuilder.forAddress("127.0.0.1", port) + .directExecutor() + .sslContext(SslContextBuilder + .forClient() + .sslProvider(SslProvider.OPENSSL) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2)) + .build() + ) + .build()); + } +} \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java new file mode 100644 index 0000000000..7cd0645a7c --- /dev/null +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.test.proxy; + +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.MessagingServiceGrpc; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.rpc.Code; +import io.grpc.Channel; +import java.net.URL; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; +import org.apache.rocketmq.test.base.GrpcBaseTest; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; +import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; +import static org.assertj.core.api.Assertions.assertThat; + +public class LocalGrpcTest extends GrpcBaseTest { + private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + + @Before + public void setUp() throws Exception { + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + GrpcMessagingProcessor processor = new GrpcMessagingProcessor(new LocalGrpcService(brokerController1)); + ConfigurationManager.getProxyConfig().setGrpcServerPort(8082); + Channel channel = setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + blockingStub = MessagingServiceGrpc.newBlockingStub(channel); + } + + @Test + public void testSendReceiveMessage() { + String group = "group"; + SendMessageResponse sendResponse = blockingStub.sendMessage(SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(broker1Name) + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId(createUniqID()) + .setPartitionId(0) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build()); + assertThat(sendResponse.getCommon() + .getStatus() + .getCode()).isEqualTo(Code.OK.getNumber()); + String messageId = sendResponse.getMessageId(); + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) + .receiveMessage(ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(broker1Name) + .build()) + .setId(0) + .build()) + .setBatchSize(16) + .setInvisibleDuration(Duration.newBuilder() + .setSeconds(3) + .build()) + .setInitializationTimestamp(Timestamp.newBuilder() + .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) + .build()) + .build()); + assertThat(receiveResponse.getCommon() + .getStatus() + .getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(receiveResponse.getMessagesCount()).isEqualTo(1); + assertThat(receiveResponse.getMessages(0) + .getSystemAttribute() + .getMessageId()).isEqualTo(messageId); + } +} diff --git a/test/src/test/resources/rmq-proxy-home/conf/broker.conf b/test/src/test/resources/rmq-proxy-home/conf/broker.conf new file mode 100644 index 0000000000..0c0b28b7b8 --- /dev/null +++ b/test/src/test/resources/rmq-proxy-home/conf/broker.conf @@ -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. + +brokerClusterName = DefaultCluster +brokerName = broker-a +brokerId = 0 +deleteWhen = 04 +fileReservedTime = 48 +brokerRole = ASYNC_MASTER +flushDiskType = ASYNC_FLUSH diff --git a/test/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml b/test/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml new file mode 100644 index 0000000000..8d0458ebf0 --- /dev/null +++ b/test/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml @@ -0,0 +1,420 @@ + + + + + + + ${user.home}/logs/rocketmqlogs/proxy.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/proxy.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/grpc.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/grpc.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker_default.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker_default.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/broker.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/broker.%i.log.gz + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/protection.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/protection.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/watermark.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/watermark.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/store.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/store.%i.log.gz + 1 + 10 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/remoting.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/remoting.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/storeerror.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/storeerror.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/transaction.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/transaction.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/lock.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/lock.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/filter.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/filter.%i.log.gz + 1 + 10 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/stats.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/stats.%i.log.gz + 1 + 5 + + + 100MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p - %m%n + UTF-8 + + + + + ${user.home}/logs/rocketmqlogs/${brokerLogDir}/commercial.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/${brokerLogDir}/commercial.%i.log.gz + 1 + 10 + + + 500MB + + + + + ${user.home}/logs/rocketmqlogs/pop.log + true + + ${user.home}/logs/rocketmqlogs/otherdays/pop.%i.log + + 1 + 20 + + + 128MB + + + %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + true + + %d{yyy-MM-dd HH\:mm\:ss,GMT+8} %p %t - %m%n + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json b/test/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json new file mode 100644 index 0000000000..f0873e2a35 --- /dev/null +++ b/test/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json @@ -0,0 +1,3 @@ +{ + "proxyMode": "cluster" +} \ No newline at end of file From 902f09c92b698a1752ab40da7c0a467630899ecd Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 15 Mar 2022 21:37:20 +0800 Subject: [PATCH 029/338] [ISSUE #3949] Fix codes for passing style checking. --- proxy/pom.xml | 4 ---- .../proxy/configuration/ProxyConfig.java | 23 ++++++++----------- .../grpc/interceptor/ContextInterceptor.java | 7 ++++-- .../proxy/grpc/service/LocalGrpcService.java | 8 ++++--- ...est.java => ForwardClientManagerTest.java} | 4 ++-- .../ConfigurationManagerTest.java | 2 +- ...Test.java => InitConfigAndLoggerTest.java} | 2 +- .../grpc/service/LocalGrpcServiceTest.java | 16 +++---------- 8 files changed, 27 insertions(+), 39 deletions(-) rename proxy/src/test/java/org/apache/rocketmq/proxy/client/{ClientManagerTest.java => ForwardClientManagerTest.java} (93%) rename proxy/src/test/java/org/apache/rocketmq/proxy/configuration/{InitConfigurationTest.java => InitConfigAndLoggerTest.java} (98%) diff --git a/proxy/pom.xml b/proxy/pom.xml index 337e94c8c6..944de82261 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -40,10 +40,6 @@ org.apache.rocketmq rocketmq-proto - - org.apache.rocketmq - rocketmq-proxy - org.apache.rocketmq rocketmq-broker diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java index a3aff93c19..bb8805dccc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/configuration/ProxyConfig.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.configuration; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; public class ProxyConfig { @@ -73,6 +72,8 @@ public class ProxyConfig { private int topicRouteThreadPoolNums = 36; private int topicRouteThreadPoolQueueCapacity = 50000; + private int longPollingReserveTimeInMillis = 10000; + public Integer getHealthCheckPort() { return healthCheckPort; } @@ -229,18 +230,6 @@ public class ProxyConfig { return forwardConsumerNum; } - public long getLongPollingReserveTimeMill() { - return longPollingReserveTimeMill; - } - - public void setLongPollingReserveTimeMill(long longPollingReserveTimeMill) { - this.longPollingReserveTimeMill = longPollingReserveTimeMill; - } - - public int getConsumerClientNum() { - return consumerClientNum; - } - public void setForwardConsumerNum(int forwardConsumerNum) { this.forwardConsumerNum = forwardConsumerNum; } @@ -332,4 +321,12 @@ public class ProxyConfig { public void setTopicRouteThreadPoolQueueCapacity(int topicRouteThreadPoolQueueCapacity) { this.topicRouteThreadPoolQueueCapacity = topicRouteThreadPoolQueueCapacity; } + + public int getLongPollingReserveTimeInMillis() { + return longPollingReserveTimeInMillis; + } + + public void setLongPollingReserveTimeInMillis(int longPollingReserveTimeInMillis) { + this.longPollingReserveTimeInMillis = longPollingReserveTimeInMillis; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java index 259f02d926..4c0a8f18ab 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java @@ -28,8 +28,11 @@ import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; public class ContextInterceptor implements ServerInterceptor { @Override - public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, - ServerCallHandler next) { + public ServerCall.Listener interceptCall( + ServerCall call, + Metadata headers, + ServerCallHandler next + ) { Context context = Context.current() .withValue(InterceptorConstants.METADATA, headers); return Contexts.interceptCall(context, call, headers, next); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index b806ec6e7a..63f0de555d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -100,7 +100,8 @@ public class LocalGrpcService implements GrpcForwardService { return null; } - @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + @Override + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { LanguageCode languageCode; String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); languageCode = LanguageCode.valueOf(language); @@ -120,7 +121,8 @@ public class LocalGrpcService implements GrpcForwardService { return CompletableFuture.completedFuture(heartbeatResponse); } - @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { + @Override + public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { LOGGER.trace("Received health check request from client: {}", request.getClientHost()); final HealthCheckResponse response = HealthCheckResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) @@ -168,7 +170,7 @@ public class LocalGrpcService implements GrpcForwardService { long timeRemaining = Context.current() .getDeadline() .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeMill(); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); if (pollTime <= 0) { pollTime = timeRemaining; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java similarity index 93% rename from proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java index d3121f32e5..6c837555ed 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java @@ -19,13 +19,13 @@ package org.apache.rocketmq.proxy.client; import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; +import org.apache.rocketmq.proxy.configuration.InitConfigAndLoggerTest; import org.junit.Test; import org.mockito.Mockito; import static org.assertj.core.api.Assertions.assertThat; -public class ClientManagerTest extends InitConfigurationTest { +public class ForwardClientManagerTest extends InitConfigAndLoggerTest { @Test public void testClientManager() throws Exception { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java index 95a3a31aad..f0b37123d2 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java @@ -22,7 +22,7 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; -public class ConfigurationManagerTest extends InitConfigurationTest { +public class ConfigurationManagerTest extends InitConfigAndLoggerTest { @Test public void testInitEnv() { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigurationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigurationTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java index 753abb923b..5cad87fac8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigurationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java @@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory; import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; -public class InitConfigurationTest { +public class InitConfigAndLoggerTest { public static String mockProxyHome = "/mock/rmq/proxy/home"; @Before diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index b78534a9fd..52c3e587fe 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -31,7 +31,6 @@ import io.grpc.Context; import io.grpc.Metadata; import io.netty.channel.ChannelHandlerContext; import java.net.InetSocketAddress; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -45,8 +44,7 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.configuration.InitConfigurationTest; +import org.apache.rocketmq.proxy.configuration.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -58,11 +56,10 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; -import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; @RunWith(MockitoJUnitRunner.class) -public class LocalGrpcServiceTest extends InitConfigurationTest { +public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { private LocalGrpcService localGrpcService; @Mock private SendMessageProcessor sendMessageProcessorMock; @@ -75,14 +72,7 @@ public class LocalGrpcServiceTest extends InitConfigurationTest { @Before public void setUp() throws Exception { - String mockProxyHome = "/mock/rmq/proxy/home"; - URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); - if (mockProxyHomeURL != null) { - mockProxyHome = mockProxyHomeURL.toURI().getPath(); - } - System.setProperty(RMQ_PROXY_HOME, mockProxyHome); - ConfigurationManager.initEnv(); - ConfigurationManager.intConfig(); + super.before(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); localGrpcService = new LocalGrpcService(brokerControllerMock); From 540ccd741c37327bcc3552453a30fdccfb5f2a49 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 16 Mar 2022 10:48:36 +0800 Subject: [PATCH 030/338] [ISSUE #3949] add grpc channel impl --- .../proxy/channel/ChannelManager.java | 34 ++++++-- .../adapter/channel/GrpcClientChannel.java | 82 +++++++++++++++++++ 2 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index d8666fa5b5..bdbfe949dd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -23,6 +23,7 @@ import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Supplier; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.configuration.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; @@ -35,21 +36,44 @@ public class ChannelManager { private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { - final String clientId = anonymousChannelId(); + return createChannel(anonymousChannelId()); + } + + public SimpleChannel createChannel(String clientId) { + return createChannel(clientId, ChannelManager::createSimpleChannelDirectly, SimpleChannel.class); + } + + public T createChannel(String clientId, Supplier creator, Class clazz) { if (Strings.isNullOrEmpty(clientId)) { LOGGER.warn("ClientId is unexpected null or empty"); - return createChannelInner(); + return creator.get(); } if (!clientIdChannelMap.containsKey(clientId)) { - clientIdChannelMap.putIfAbsent(clientId, createChannelInner()); + clientIdChannelMap.putIfAbsent(clientId, creator.get()); } - SimpleChannel channel = clientIdChannelMap.get(clientId); + T channel = clazz.cast(clientIdChannelMap.get(clientId)); channel.updateLastAccessTime(); return channel; } + public T getChannel(String clientId, Class clazz) { + SimpleChannel channel = clientIdChannelMap.get(clientId); + if (channel == null) { + return null; + } + return clazz.cast(channel); + } + + public T removeChannel(String clientId, Class clazz) { + SimpleChannel channel = clientIdChannelMap.remove(clientId); + if (channel == null) { + return null; + } + return clazz.cast(channel); + } + private String anonymousChannelId() { final String clientHost = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.REMOTE_ADDRESS); @@ -58,7 +82,7 @@ public class ChannelManager { return clientHost + "@" + localAddress; } - private SimpleChannel createChannelInner() { + public static SimpleChannel createSimpleChannelDirectly() { final String clientHost = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.REMOTE_ADDRESS); final String localAddress = InterceptorConstants.METADATA.get(Context.current()) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java new file mode 100644 index 0000000000..a13d0327fe --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -0,0 +1,82 @@ +/* + * 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.grpc.adapter.channel; + +import apache.rocketmq.v1.PollCommandResponse; +import io.netty.channel.ChannelFuture; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannel; + +public class GrpcClientChannel extends SimpleChannel { + + private static final Map/* clientId */> GROUP_CLIENT_IDS = new ConcurrentHashMap<>(); + + private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); + + public GrpcClientChannel(SimpleChannel simpleChannel) { + super(simpleChannel); + } + + public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId) { + GrpcClientChannel channel = channelManager.createChannel( + buildKey(group, clientId), + () -> new GrpcClientChannel(ChannelManager.createSimpleChannelDirectly()), + GrpcClientChannel.class); + + GROUP_CLIENT_IDS.compute(group, (groupKey, clientIds) -> { + if (clientIds == null) { + clientIds = new CopyOnWriteArrayList<>(); + } + clientIds.add(clientId); + return clientIds; + }); + return channel; + } + + public static void addClientObserver(ChannelManager channelManager, String group, String clientId, CompletableFuture future) { + GrpcClientChannel channel = getChannel(channelManager, group, clientId); + channel.pollCommandResponseFutureRef.set(future); + } + + public static GrpcClientChannel getChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannel.class); + } + + public static GrpcClientChannel removeChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannel.class); + } + + private static String buildKey(String group, String clientId) { + return group + "@" + clientId; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + CompletableFuture future = pollCommandResponseFutureRef.get(); + if (msg instanceof PollCommandResponse) { + PollCommandResponse response = (PollCommandResponse) msg; + future.complete(response); + } + return super.writeAndFlush(msg); + } +} From db7ab9b61c3124991aefe36f18b075393df73b1b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 11:11:03 +0800 Subject: [PATCH 031/338] [ISSUE #3949] Refector Channels --- .../apache/rocketmq/proxy/channel/ChannelManager.java | 4 ++++ .../proxy/grpc/adapter/channel/GrpcClientChannel.java | 6 +++--- .../grpc/adapter/channel/ReceiveMessageChannel.java | 10 +++------- .../proxy/grpc/adapter/channel/SendMessageChannel.java | 10 +++------- .../rocketmq/proxy/grpc/service/LocalGrpcService.java | 4 ++-- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index bdbfe949dd..ca612ef798 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -43,6 +43,10 @@ public class ChannelManager { return createChannel(clientId, ChannelManager::createSimpleChannelDirectly, SimpleChannel.class); } + public T createChannel(Supplier creator, Class clazz) { + return createChannel(anonymousChannelId(), creator, clazz); + } + public T createChannel(String clientId, Supplier creator, Class clazz) { if (Strings.isNullOrEmpty(clientId)) { LOGGER.warn("ClientId is unexpected null or empty"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index a13d0327fe..de8bfa906a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -33,14 +33,14 @@ public class GrpcClientChannel extends SimpleChannel { private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); - public GrpcClientChannel(SimpleChannel simpleChannel) { - super(simpleChannel); + public GrpcClientChannel() { + super(ChannelManager.createSimpleChannelDirectly()); } public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), - () -> new GrpcClientChannel(ChannelManager.createSimpleChannelDirectly()), + GrpcClientChannel::new, GrpcClientChannel.class); GROUP_CLIENT_IDS.compute(group, (groupKey, clientIds) -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java index 6319d7d2d8..acc280a73f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java @@ -20,8 +20,8 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import io.netty.channel.ChannelFuture; +import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -29,12 +29,8 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ReceiveMessageChannel extends InvocationChannel { private final ReceiveMessageResponseHandler handler; - public static ReceiveMessageChannel create(SimpleChannel other, ReceiveMessageResponseHandler handler) { - return new ReceiveMessageChannel(other, handler); - } - - private ReceiveMessageChannel(SimpleChannel simpleChannel, ReceiveMessageResponseHandler handler) { - super(simpleChannel); + public ReceiveMessageChannel(ReceiveMessageResponseHandler handler) { + super(ChannelManager.createSimpleChannelDirectly()); this.handler = handler; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java index 08894d6fd3..d0037d43fb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java @@ -20,8 +20,8 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.netty.channel.ChannelFuture; +import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -29,12 +29,8 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class SendMessageChannel extends InvocationChannel { private final SendMessageResponseHandler handler; - public static SendMessageChannel create(SimpleChannel simpleChannel, SendMessageResponseHandler handler) { - return new SendMessageChannel(simpleChannel, handler); - } - - private SendMessageChannel(SimpleChannel other, SendMessageResponseHandler handler) { - super(other); + public SendMessageChannel(SendMessageResponseHandler handler) { + super(ChannelManager.createSimpleChannelDirectly()); this.handler = handler; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 63f0de555d..08d397bed8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -139,7 +139,7 @@ public class LocalGrpcService implements GrpcForwardService { command.makeCustomHeaderToNet(); SendMessageResponseHandler handler = new SendMessageResponseHandler(message.getSystemAttribute().getMessageId()); - SendMessageChannel channel = SendMessageChannel.create(channelManager.createChannel(), handler); + SendMessageChannel channel = channelManager.createChannel(() -> new SendMessageChannel(handler), SendMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); InvocationContext context @@ -179,7 +179,7 @@ public class LocalGrpcService implements GrpcForwardService { command.makeCustomHeaderToNet(); ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(); - ReceiveMessageChannel channel = ReceiveMessageChannel.create(channelManager.createChannel(), handler); + ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); InvocationContext context From 63211bdcf84866187d4882ee8f9e4287d3eff599 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 16 Mar 2022 14:19:10 +0800 Subject: [PATCH 032/338] [ISSUE #3949] Do some renaming work. --- .../rocketmq/proxy/HealthCheckServer.java | 2 +- .../apache/rocketmq/proxy/ProxyStartup.java | 4 +- .../proxy/channel/ChannelManager.java | 2 +- .../proxy/client/DefaultForwardClient.java | 2 +- .../proxy/client/ForwardProducer.java | 2 +- .../proxy/client/ForwardReadConsumer.java | 2 +- .../proxy/client/ForwardWriteConsumer.java | 24 ++++++--- .../proxy/client/TopicRouteCache.java | 4 +- .../factory/AbstractMQClientFactory.java | 11 ++-- .../client/factory/ForwardClientFactory.java | 6 +-- .../proxy/client/factory/MQClientFactory.java | 39 ++++++++++++-- .../client/factory/MQClientFactoryImpl.java | 52 ------------------- .../factory/TransactionalProducerFactory.java | 6 ++- .../Configuration.java | 2 +- .../ConfigurationManager.java | 2 +- .../ProxyConfig.java | 2 +- .../rocketmq/proxy/grpc/GrpcServer.java | 2 +- .../grpc/interceptor/ContextInterceptor.java | 3 +- .../grpc/interceptor/HeaderInterceptor.java | 16 +++--- .../grpc/service/ClusterGrpcService.java | 10 ++-- .../proxy/grpc/service/LocalGrpcService.java | 2 +- .../client/ForwardClientManagerTest.java | 4 +- .../ConfigurationManagerTest.java | 2 +- .../InitConfigAndLoggerTest.java | 4 +- .../grpc/service/LocalGrpcServiceTest.java | 2 +- .../rocketmq/test/proxy/LocalGrpcTest.java | 4 +- 26 files changed, 101 insertions(+), 110 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{configuration => config}/Configuration.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{configuration => config}/ConfigurationManager.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{configuration => config}/ProxyConfig.java (99%) rename proxy/src/test/java/org/apache/rocketmq/proxy/{configuration => config}/ConfigurationManagerTest.java (97%) rename proxy/src/test/java/org/apache/rocketmq/proxy/{configuration => config}/InitConfigAndLoggerTest.java (94%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java index 124bc282b2..ed5e977a39 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -23,7 +23,7 @@ import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.common.StartAndShutdown; public class HealthCheckServer implements StartAndShutdown { 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 8379fcf66c..808d748b7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -26,8 +26,8 @@ import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.BrokerStartup; import org.apache.rocketmq.client.log.ClientLogger; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.configuration.ProxyConfig; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index ca612ef798..53bf9e33c8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -25,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.slf4j.Logger; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java index de3d950160..ede03992f9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java @@ -23,7 +23,7 @@ import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.exception.RemotingException; public class DefaultForwardClient extends AbstractForwardClient { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java index 8254b83fb1..734af13455 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java @@ -24,7 +24,7 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ForwardProducer extends AbstractForwardClient { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java index f3672ea370..37dce5a86a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java @@ -23,7 +23,7 @@ import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; public class ForwardReadConsumer extends AbstractForwardClient { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java index 26dedbbd0d..446d9f023f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java @@ -23,7 +23,7 @@ import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.exception.RemotingException; public class ForwardWriteConsumer extends AbstractForwardClient { @@ -52,18 +52,28 @@ public class ForwardWriteConsumer extends AbstractForwardClient { return CID_PREFIX; } - public CompletableFuture ackMessage(String address, AckMessageRequestHeader requestHeader, - long timeoutMillis) { + public CompletableFuture ackMessage( + String address, + AckMessageRequestHeader requestHeader, + long timeoutMillis + ) { return getClient().ackMessage(address, requestHeader, timeoutMillis); } - public CompletableFuture changeInvisibleTimeAsync(String address, String brokerName, - ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture changeInvisibleTimeAsync( + String address, + String brokerName, + ChangeInvisibleTimeRequestHeader requestHeader, + long timeoutMillis + ) { return getClient().changeInvisibleTimeAsync(address, brokerName, requestHeader, timeoutMillis); } - public void updateConsumerOffsetOneWay(String brokerAddr, UpdateConsumerOffsetRequestHeader header, - long timeoutMillis) throws RemotingException, InterruptedException { + public void updateConsumerOffsetOneWay( + String brokerAddr, + UpdateConsumerOffsetRequestHeader header, + long timeoutMillis + ) throws RemotingException, InterruptedException { getClient().updateConsumerOffsetOneWay(brokerAddr, header, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java index 33091ce136..e9dae720e3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/TopicRouteCache.java @@ -31,8 +31,8 @@ import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.common.RetainCacheLoader; import org.apache.rocketmq.proxy.common.RocketMQHelper; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.configuration.ProxyConfig; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java index 35221594f1..fc28f8ba32 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java @@ -23,8 +23,7 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class AbstractMQClientFactory implements MQClientFactory { - +public abstract class AbstractMQClientFactory { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMQClientFactory.class); protected Map cacheTable = new ConcurrentHashMap<>(); @@ -48,7 +47,7 @@ public abstract class AbstractMQClientFactory implements MQClientFactory { return nettyClientConfig; } - @Override +// @Override public T getOne(String instanceName, int bootstrapWorkerThreads) { if (cacheTable.containsKey(instanceName)) { return cacheTable.get(instanceName); @@ -57,8 +56,8 @@ public abstract class AbstractMQClientFactory implements MQClientFactory { T object; try { object = this.newOne(instanceName, rpcHook, bootstrapWorkerThreads); - } catch (Throwable throwable) { - throw new RuntimeException(throwable); + } catch (Throwable t) { + throw new RuntimeException(t); } T old = cacheTable.putIfAbsent(instanceName, object); if (old == null) { @@ -72,7 +71,7 @@ public abstract class AbstractMQClientFactory implements MQClientFactory { return object; } - @Override +// @Override public void shutdownAll() { this.cacheTable.forEach((k, v) -> { try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java index 55e709cb4d..f27383c9f9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java @@ -22,20 +22,20 @@ import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.RPCHook; public class ForwardClientFactory implements StartAndShutdown { private RPCHook rpcHook = null; - private final MQClientFactoryImpl mqClientFactory; + private final MQClientFactory mqClientFactory; private final TransactionalProducerFactory transactionalProducerFactory; public ForwardClientFactory(TransactionStateChecker transactionStateChecker) { this.init(); - this.mqClientFactory = new MQClientFactoryImpl(this.rpcHook); + this.mqClientFactory = new MQClientFactory(this.rpcHook); this.transactionalProducerFactory = new TransactionalProducerFactory(this.rpcHook, transactionStateChecker); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java index de43082292..d95667dea9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java @@ -16,7 +16,38 @@ */ package org.apache.rocketmq.proxy.client.factory; -public interface MQClientFactory { - T getOne(String instanceName, int bootstrapWorkerThreads); - void shutdownAll(); -} \ No newline at end of file +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.proxy.client.processor.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.remoting.RPCHook; + +public class MQClientFactory extends AbstractMQClientFactory { + + public MQClientFactory(RPCHook rpcHook) { + super(rpcHook); + } + + @Override + MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + ClientConfig clientConfig = new ClientConfig(); + clientConfig.setInstanceName(instanceName); + + return new MQClientAPIExtImpl( + createNettyClientConfig(bootstrapWorkerThreads), + new DoNothingClientRemotingProcessor(null), + rpcHook, + clientConfig + ); + } + + @Override + boolean tryStart(MQClientAPIExtImpl client) { + client.start(); + return true; + } + + @Override + void shutdown(MQClientAPIExtImpl client) { + client.shutdown(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java deleted file mode 100644 index d4a4979c24..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactoryImpl.java +++ /dev/null @@ -1,52 +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.proxy.client.factory; - -import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; -import org.apache.rocketmq.proxy.client.processor.DoNothingClientRemotingProcessor; -import org.apache.rocketmq.remoting.RPCHook; - -public class MQClientFactoryImpl extends AbstractMQClientFactory { - - public MQClientFactoryImpl(RPCHook rpcHook) { - super(rpcHook); - } - - @Override - MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.setInstanceName(instanceName); - - return new MQClientAPIExtImpl( - createNettyClientConfig(bootstrapWorkerThreads), - new DoNothingClientRemotingProcessor(null), - rpcHook, - clientConfig); - } - - @Override - boolean tryStart(MQClientAPIExtImpl client) { - client.start(); - return true; - } - - @Override - void shutdown(MQClientAPIExtImpl client) { - client.shutdown(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java index 6168e9e358..6902929418 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java @@ -32,11 +32,15 @@ public class TransactionalProducerFactory extends AbstractMQClientFactory next ) { - Context context = Context.current() - .withValue(InterceptorConstants.METADATA, headers); + Context context = Context.current().withValue(InterceptorConstants.METADATA, headers); return Contexts.interceptCall(context, call, headers, next); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java index 64688dd728..698f75d00e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java @@ -29,26 +29,26 @@ import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; public class HeaderInterceptor implements ServerInterceptor { @Override - public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, - ServerCallHandler next) { - SocketAddress remoteSocketAddress = call.getAttributes() - .get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR); + public ServerCall.Listener interceptCall( + ServerCall call, + Metadata headers, + ServerCallHandler next + ) { + SocketAddress remoteSocketAddress = call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR); String remoteAddress = parseSocketAddress(remoteSocketAddress); headers.put(InterceptorConstants.REMOTE_ADDRESS, remoteAddress); - SocketAddress localSocketAddress = call.getAttributes() - .get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR); + SocketAddress localSocketAddress = call.getAttributes().get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR); String localAddress = parseSocketAddress(localSocketAddress); headers.put(InterceptorConstants.LOCAL_ADDRESS, localAddress); return next.startCall(call, headers); } - private String parseSocketAddress(SocketAddress socketAddress) { if (socketAddress instanceof InetSocketAddress) { InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; return HostAndPort.fromParts(inetSocketAddress.getAddress() - .getHostAddress(), inetSocketAddress.getPort()) + .getHostAddress(), inetSocketAddress.getPort()) .toString(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index a7d1404eda..e39740fc2b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -64,17 +64,17 @@ import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ForwardClientManager clientManager; + private final ForwardClientManager forwardClientManager; private final ProducerService producerService; private final RouteService routeService; public ClusterGrpcService() { - this.clientManager = new ForwardClientManager(checkData -> { + this.forwardClientManager = new ForwardClientManager(checkData -> { }); - this.producerService = new ProducerService(clientManager); - this.routeService = new RouteService(clientManager); + this.producerService = new ProducerService(forwardClientManager); + this.routeService = new RouteService(forwardClientManager); - this.appendStartAndShutdown(this.clientManager); + this.appendStartAndShutdown(this.forwardClientManager); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 08d397bed8..9c5133b6fc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -69,7 +69,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java index 6c837555ed..710affa028 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java @@ -18,8 +18,8 @@ package org.apache.rocketmq.proxy.client; import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; -import org.apache.rocketmq.proxy.configuration.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.junit.Test; import org.mockito.Mockito; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java similarity index 97% rename from proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java index f0b37123d2..669efe8ca2 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/ConfigurationManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.configuration; +package org.apache.rocketmq.proxy.config; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java similarity index 94% rename from proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java index 5cad87fac8..5b2fea4e38 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/configuration/InitConfigAndLoggerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.configuration; +package org.apache.rocketmq.proxy.config; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; @@ -26,7 +26,7 @@ import org.junit.After; import org.junit.Before; import org.slf4j.LoggerFactory; -import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; +import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; public class InitConfigAndLoggerTest { public static String mockProxyHome = "/mock/rmq/proxy/home"; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 52c3e587fe..3d831a751a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -44,7 +44,7 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.proxy.configuration.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java index 7cd0645a7c..387764ad3b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java @@ -33,7 +33,7 @@ import com.google.rpc.Code; import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.proxy.configuration.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; import org.apache.rocketmq.test.base.GrpcBaseTest; @@ -41,7 +41,7 @@ import org.junit.Before; import org.junit.Test; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; -import static org.apache.rocketmq.proxy.configuration.ConfigurationManager.RMQ_PROXY_HOME; +import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; public class LocalGrpcTest extends GrpcBaseTest { From 5c6fccacc805c63e26ba99a885a0a275b5f00cfb Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 16 Mar 2022 15:09:49 +0800 Subject: [PATCH 033/338] [ISSUE #3949] Do some renaming work. --- ...heLoader.java => AbstractCacheLoader.java} | 9 +++++---- .../AbstractForwardClient.java | 4 ++-- .../ConnectorManager.java} | 11 +++++----- .../DefaultForwardClient.java | 13 +++++++----- .../ForwardProducer.java | 4 ++-- .../ForwardReadConsumer.java | 4 ++-- .../ForwardWriteConsumer.java | 4 ++-- .../factory/AbstractClientFactory.java} | 14 ++++++------- .../factory/ForwardClientFactory.java | 8 ++++---- .../factory/MQClientFactory.java | 12 +++++------ .../factory/TransactionProducerFactory.java} | 16 +++++++-------- .../DoNothingClientRemotingProcessor.java | 2 +- .../ProxyClientRemotingProcessor.java | 8 ++++---- .../route/MessageQueueSelector.java | 2 +- .../route/MessageQueueWrapper.java | 2 +- .../route/SelectableMessageQueue.java | 2 +- .../route}/TopicRouteCache.java | 12 +++++------ .../route/TopicRouteHelper.java} | 20 ++++++++----------- .../route/TopicRouteWrapper.java | 2 +- .../transaction/TransactionId.java | 2 +- .../TransactionStateCheckRequest.java | 2 +- .../transaction/TransactionStateChecker.java | 2 +- .../grpc/service/ClusterGrpcService.java | 6 +++--- .../grpc/service/cluster/BaseService.java | 6 +++--- .../grpc/service/cluster/ConsumerService.java | 4 ++-- .../grpc/service/cluster/ProducerService.java | 6 +++--- .../grpc/service/cluster/RouteService.java | 12 +++++------ .../ForwardClientManagerTest.java | 6 +++--- .../grpc/service/cluster/BaseServiceTest.java | 14 ++++++------- .../service/cluster/ProducerServiceTest.java | 2 +- .../service/cluster/RouteServiceTest.java | 3 +-- 31 files changed, 106 insertions(+), 108 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/common/{RetainCacheLoader.java => AbstractCacheLoader.java} (83%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/AbstractForwardClient.java (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client/ForwardClientManager.java => connector/ConnectorManager.java} (86%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/DefaultForwardClient.java (87%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/ForwardProducer.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/ForwardReadConsumer.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/ForwardWriteConsumer.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client/factory/AbstractMQClientFactory.java => connector/factory/AbstractClientFactory.java} (86%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/factory/ForwardClientFactory.java (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/factory/MQClientFactory.java (76%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client/factory/TransactionalProducerFactory.java => connector/factory/TransactionProducerFactory.java} (71%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/processor/DoNothingClientRemotingProcessor.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/processor/ProxyClientRemotingProcessor.java (92%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/route/MessageQueueSelector.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/route/MessageQueueWrapper.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/route/SelectableMessageQueue.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector/route}/TopicRouteCache.java (93%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{common/RocketMQHelper.java => connector/route/TopicRouteHelper.java} (72%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/route/TopicRouteWrapper.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/transaction/TransactionId.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/transaction/TransactionStateCheckRequest.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{client => connector}/transaction/TransactionStateChecker.java (94%) rename proxy/src/test/java/org/apache/rocketmq/proxy/{client => connector}/ForwardClientManagerTest.java (90%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractCacheLoader.java similarity index 83% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractCacheLoader.java index 80d49ed8e3..581caffdbd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RetainCacheLoader.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractCacheLoader.java @@ -20,16 +20,17 @@ import com.google.common.cache.CacheLoader; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; import java.util.concurrent.ThreadPoolExecutor; +import javax.annotation.Nonnull; -public abstract class RetainCacheLoader extends CacheLoader { +public abstract class AbstractCacheLoader extends CacheLoader { private final ThreadPoolExecutor cacheRefreshExecutor; - public RetainCacheLoader(ThreadPoolExecutor cacheRefreshExecutor) { + public AbstractCacheLoader(ThreadPoolExecutor cacheRefreshExecutor) { this.cacheRefreshExecutor = cacheRefreshExecutor; } @Override - public ListenableFuture reload(K key, V oldValue) throws Exception { + public ListenableFuture reload(@Nonnull K key, @Nonnull V oldValue) throws Exception { ListenableFutureTask task = ListenableFutureTask.create(() -> { try { return getDirectly(key); @@ -43,7 +44,7 @@ public abstract class RetainCacheLoader extends CacheLoader { } @Override - public V load(K key) throws Exception { + public V load(@Nonnull K key) throws Exception { return getDirectly(key); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 480554d6b8..0fa3c3746b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -14,11 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; import java.util.concurrent.ThreadLocalRandom; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; public abstract class AbstractForwardClient implements StartAndShutdown { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java index 85dc298a8b..01ec55fb62 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java @@ -14,13 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; -import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -public class ForwardClientManager extends AbstractStartAndShutdown { +public class ConnectorManager extends AbstractStartAndShutdown { private final ForwardClientFactory forwardClientFactory; private final DefaultForwardClient defaultForwardClient; private final ForwardProducer forwardProducer; @@ -29,7 +30,7 @@ public class ForwardClientManager extends AbstractStartAndShutdown { private final TopicRouteCache topicRouteCache; - public ForwardClientManager(TransactionStateChecker transactionStateChecker) { + public ConnectorManager(TransactionStateChecker transactionStateChecker) { this.forwardClientFactory = new ForwardClientFactory(transactionStateChecker); this.defaultForwardClient = new DefaultForwardClient(this.forwardClientFactory); this.forwardProducer = new ForwardProducer(this.forwardClientFactory); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java similarity index 87% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index ede03992f9..1c298311f7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -22,15 +22,15 @@ import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.remoting.exception.RemotingException; public class DefaultForwardClient extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; - public DefaultForwardClient(ForwardClientFactory clientFactory) { - super(clientFactory); + public DefaultForwardClient(ForwardClientFactory forwardClientFactory) { + super(forwardClientFactory); } @Override @@ -52,7 +52,10 @@ public class DefaultForwardClient extends AbstractForwardClient { } public CompletableFuture> getConsumerListByGroup( - String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis) { + String brokerAddr, + GetConsumerListByGroupRequestHeader requestHeader, + long timeoutMillis + ) { return getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 734af13455..cc0e5ba9ce 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; @@ -23,7 +23,7 @@ import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 37dce5a86a..0aa0b30d70 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.PopResult; @@ -22,7 +22,7 @@ import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; public class ForwardReadConsumer extends AbstractForwardClient { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 446d9f023f..5d3f5c2035 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; @@ -22,7 +22,7 @@ import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; -import org.apache.rocketmq.proxy.client.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.exception.RemotingException; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java index fc28f8ba32..7e0519097b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.factory; +package org.apache.rocketmq.proxy.connector.factory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -23,21 +23,21 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class AbstractMQClientFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMQClientFactory.class); +public abstract class AbstractClientFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientFactory.class); protected Map cacheTable = new ConcurrentHashMap<>(); protected RPCHook rpcHook; - public AbstractMQClientFactory(RPCHook rpcHook) { + public AbstractClientFactory(RPCHook rpcHook) { this.rpcHook = rpcHook; } - abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) throws Throwable; + protected abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) throws Throwable; - abstract boolean tryStart(T t); + protected abstract boolean tryStart(T t); - abstract void shutdown(T t); + protected abstract void shutdown(T t); protected static NettyClientConfig createNettyClientConfig(int bootstrapWorkerThreads) { NettyClientConfig nettyClientConfig = new NettyClientConfig(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java index f27383c9f9..08b43acf2c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/ForwardClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.factory; +package org.apache.rocketmq.proxy.connector.factory; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.RPCHook; @@ -30,13 +30,13 @@ public class ForwardClientFactory implements StartAndShutdown { private RPCHook rpcHook = null; private final MQClientFactory mqClientFactory; - private final TransactionalProducerFactory transactionalProducerFactory; + private final TransactionProducerFactory transactionalProducerFactory; public ForwardClientFactory(TransactionStateChecker transactionStateChecker) { this.init(); this.mqClientFactory = new MQClientFactory(this.rpcHook); - this.transactionalProducerFactory = new TransactionalProducerFactory(this.rpcHook, transactionStateChecker); + this.transactionalProducerFactory = new TransactionProducerFactory(this.rpcHook, transactionStateChecker); } private void init() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java similarity index 76% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java index d95667dea9..3b9a75f33b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/MQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java @@ -14,21 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.factory; +package org.apache.rocketmq.proxy.connector.factory; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; -import org.apache.rocketmq.proxy.client.processor.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.connector.processor.DoNothingClientRemotingProcessor; import org.apache.rocketmq.remoting.RPCHook; -public class MQClientFactory extends AbstractMQClientFactory { +public class MQClientFactory extends AbstractClientFactory { public MQClientFactory(RPCHook rpcHook) { super(rpcHook); } @Override - MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + protected MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { ClientConfig clientConfig = new ClientConfig(); clientConfig.setInstanceName(instanceName); @@ -41,13 +41,13 @@ public class MQClientFactory extends AbstractMQClientFactory } @Override - boolean tryStart(MQClientAPIExtImpl client) { + protected boolean tryStart(MQClientAPIExtImpl client) { client.start(); return true; } @Override - void shutdown(MQClientAPIExtImpl client) { + protected void shutdown(MQClientAPIExtImpl client) { client.shutdown(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java similarity index 71% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java index 6902929418..a97727c11d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/factory/TransactionalProducerFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java @@ -14,24 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.factory; +package org.apache.rocketmq.proxy.connector.factory; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; -import org.apache.rocketmq.proxy.client.processor.ProxyClientRemotingProcessor; -import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.connector.processor.ProxyClientRemotingProcessor; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.remoting.RPCHook; -public class TransactionalProducerFactory extends AbstractMQClientFactory { +public class TransactionProducerFactory extends AbstractClientFactory { private final TransactionStateChecker transactionStateChecker; - public TransactionalProducerFactory(RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { + public TransactionProducerFactory(RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { super(rpcHook); this.transactionStateChecker = transactionStateChecker; } @Override - MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + public MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { ClientConfig clientConfig = new ClientConfig(); clientConfig.setInstanceName(instanceName); @@ -44,13 +44,13 @@ public class TransactionalProducerFactory extends AbstractMQClientFactory { + protected abstract class AbstractTopicRouteCacheLoader extends AbstractCacheLoader { public AbstractTopicRouteCacheLoader() { super(cacheRefreshExecutor); @@ -124,7 +122,7 @@ public class TopicRouteCache { } return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; } catch (Exception e) { - if (RocketMQHelper.isTopicNotExistError(e)) { + if (TopicRouteHelper.isTopicNotExistError(e)) { return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; } throw e; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java similarity index 72% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java index a1488cf017..97b345d703 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RocketMQHelper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java @@ -14,14 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.common; +package org.apache.rocketmq.proxy.connector.route; import org.apache.rocketmq.client.common.ClientErrorCode; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.protocol.ResponseCode; -public class RocketMQHelper { +public class TopicRouteHelper { public static boolean isTopicNotExistError(Throwable e) { if (e instanceof MQBrokerException) { @@ -29,24 +29,20 @@ public class RocketMQHelper { return true; } } - if (e instanceof MQClientException) { - if (((MQClientException) e).getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { - return true; - } - if (((MQClientException) e).getResponseCode() == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION) { + if (e instanceof MQClientException) { + int code = ((MQClientException) e).getResponseCode(); + if (code == ResponseCode.TOPIC_NOT_EXIST || code == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION) { return true; } Throwable cause = e.getCause(); if (cause instanceof MQClientException) { - if (((MQClientException) cause).getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) { - return true; - } - - return ((MQClientException) cause).getResponseCode() == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION; + int causeCode = ((MQClientException) cause).getResponseCode(); + return causeCode == ResponseCode.TOPIC_NOT_EXIST || causeCode == ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION; } } + return false; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java index 9a3c69cbc5..a08bd3aa52 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/route/TopicRouteWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.route; +package org.apache.rocketmq.proxy.connector.route; import java.util.HashMap; import java.util.List; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index 05da6904cd..63eb8b3f08 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.transaction; +package org.apache.rocketmq.proxy.connector.transaction; import java.net.InetAddress; import java.net.InetSocketAddress; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java index 73cab80586..ad6b5ac0d6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateCheckRequest.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.transaction; +package org.apache.rocketmq.proxy.connector.transaction; import org.apache.rocketmq.common.message.MessageExt; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java index 6cea826cb2..506aa0154c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/client/transaction/TransactionStateChecker.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.client.transaction; +package org.apache.rocketmq.proxy.connector.transaction; public interface TransactionStateChecker { void checkTransactionState(TransactionStateCheckRequest checkData); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index e39740fc2b..59a0df7f1c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -54,7 +54,7 @@ import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; @@ -64,12 +64,12 @@ import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ForwardClientManager forwardClientManager; + private final ConnectorManager forwardClientManager; private final ProducerService producerService; private final RouteService routeService; public ClusterGrpcService() { - this.forwardClientManager = new ForwardClientManager(checkData -> { + this.forwardClientManager = new ConnectorManager(checkData -> { }); this.producerService = new ProducerService(forwardClientManager); this.routeService = new RouteService(forwardClientManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index b9837ef2a1..9178a1cea7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -16,13 +16,13 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; public class BaseService { - protected final ForwardClientManager clientManager; + protected final ConnectorManager clientManager; - public BaseService(ForwardClientManager clientManager) { + public BaseService(ConnectorManager clientManager) { this.clientManager = clientManager; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index cc898d16ab..9f091f9fb9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -20,11 +20,11 @@ import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.proxy.client.ForwardClientManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; public class ConsumerService extends BaseService { - public ConsumerService(ForwardClientManager clientManager) { + public ConsumerService(ConnectorManager clientManager) { super(clientManager); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 8cabdf0204..5da401fba1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -25,8 +25,8 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.client.ForwardClientManager; -import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; @@ -42,7 +42,7 @@ public class ProducerService extends BaseService { private volatile ProducerServiceHook producerServiceHook = null; private volatile MessageQueueSelector messageQueueSelector = new DefaultMessageQueueSelector(); - public ProducerService(ForwardClientManager clientManager) { + public ProducerService(ConnectorManager clientManager) { super(clientManager); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 3809e8073e..3032458311 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -34,10 +34,10 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.client.ForwardClientManager; -import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.common.RocketMQHelper; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; @@ -47,7 +47,7 @@ public class RouteService extends BaseService { private volatile QueryRouteHook queryRouteHook = null; private volatile QueryAssignmentHook queryAssignmentHook = null; - public RouteService(ForwardClientManager clientManager) { + public RouteService(ConnectorManager clientManager) { super(clientManager); } @@ -126,7 +126,7 @@ public class RouteService extends BaseService { .build(); future.complete(response); } catch (Throwable t) { - if (RocketMQHelper.isTopicNotExistError(t)) { + if (TopicRouteHelper.isTopicNotExistError(t)) { future.complete(QueryRouteResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.NOT_FOUND, t.getMessage())) .build()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java similarity index 90% rename from proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java index 710affa028..b2061744cb 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/client/ForwardClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java @@ -15,9 +15,9 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.client; +package org.apache.rocketmq.proxy.connector; -import org.apache.rocketmq.proxy.client.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.junit.Test; @@ -30,7 +30,7 @@ public class ForwardClientManagerTest extends InitConfigAndLoggerTest { @Test public void testClientManager() throws Exception { TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); - ForwardClientManager clientManager = new ForwardClientManager(mockedTransactionStateChecker); + ConnectorManager clientManager = new ConnectorManager(mockedTransactionStateChecker); clientManager.start(); assertThat(clientManager.getDefaultForwardClient()).isNotNull(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java index 9a6ab623ae..b29a248cb8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java @@ -16,12 +16,12 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import org.apache.rocketmq.proxy.client.ForwardClientManager; -import org.apache.rocketmq.proxy.client.DefaultForwardClient; -import org.apache.rocketmq.proxy.client.ForwardProducer; -import org.apache.rocketmq.proxy.client.ForwardReadConsumer; -import org.apache.rocketmq.proxy.client.TopicRouteCache; -import org.apache.rocketmq.proxy.client.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.DefaultForwardClient; +import org.apache.rocketmq.proxy.connector.ForwardProducer; +import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.junit.Before; import org.junit.Ignore; import org.junit.runner.RunWith; @@ -35,7 +35,7 @@ import static org.mockito.Mockito.when; public abstract class BaseServiceTest { @Mock - protected ForwardClientManager clientManager; + protected ConnectorManager clientManager; @Mock protected DefaultForwardClient defaultClient; @Mock diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 2ec8bb4602..90a9a3e6ca 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -35,7 +35,7 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.client.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 39ee582e6a..458dcb32b6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -19,13 +19,12 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.client.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; public class RouteServiceTest extends BaseServiceTest { From 77d7da51c4c9edfebc8378881a8873060e70f844 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 11:33:31 +0800 Subject: [PATCH 034/338] [ISSUE #3949] Implement ack and nack --- .../rocketmq/broker/BrokerController.java | 8 + .../common/consumer/ReceiptHandle.java | 223 ++++++++++++++++++ .../rocketmq/proxy/grpc/common/Converter.java | 36 +++ .../proxy/grpc/service/LocalGrpcService.java | 50 +++- 4 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java 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 2fdb6f83dd..44a4e902dd 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -1144,6 +1144,14 @@ public class BrokerController { return popMessageProcessor; } + public AckMessageProcessor getAckMessageProcessor() { + return ackMessageProcessor; + } + + public ChangeInvisibleTimeProcessor getChangeInvisibleTimeProcessor() { + return changeInvisibleTimeProcessor; + } + protected void shutdownBasicService() { shutdown = true; diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java new file mode 100644 index 0000000000..b05db4602c --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -0,0 +1,223 @@ +/* + * 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.common.consumer; + +import java.util.Arrays; +import java.util.List; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageConst; + +public class ReceiptHandle { + private static final String SEPARATOR = MessageConst.KEY_SEPARATOR; + private static final String NORMAL_TOPIC = "0"; + private static final String RETRY_TOPIC = "1"; + private final long startOffset; + private final long retrieveTime; + private final long invisibleTime; + private final long nextVisibleTime; + private final int reviveQueueId; + private final String topic; + private final String brokerName; + private final int queueId; + private final long offset; + private final String receiptHandle; + + public String encode() { + String t = NORMAL_TOPIC; + if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { + t = RETRY_TOPIC; + } + return startOffset + SEPARATOR + retrieveTime + SEPARATOR + invisibleTime + SEPARATOR + reviveQueueId + SEPARATOR + t + SEPARATOR + brokerName + SEPARATOR + queueId + SEPARATOR + offset; + } + + public boolean isExpired() { + return nextVisibleTime <= System.currentTimeMillis(); + } + + public static ReceiptHandle decode(String receiptHandle) { + List dataList = Arrays.asList(receiptHandle.split(SEPARATOR)); + if (dataList.size() < 8) { + throw new IllegalArgumentException("Parse failed, dataList size " + dataList.size()); + } + long startOffset = Long.parseLong(dataList.get(0)); + long retrieveTime = Long.parseLong(dataList.get(1)); + long invisibleTime = Long.parseLong(dataList.get(2)); + int reviveQueueId = Integer.parseInt(dataList.get(3)); + String topic = dataList.get(4); + String brokerName = dataList.get(5); + int queueId = Integer.parseInt(dataList.get(6)); + long offset = Long.parseLong(dataList.get(7)); + return new ReceiptHandleBuilder() + .startOffset(startOffset) + .retrieveTime(retrieveTime) + .invisibleTime(invisibleTime) + .reviveQueueId(reviveQueueId) + .topic(topic) + .brokerName(brokerName) + .queueId(queueId) + .offset(offset) + .nextVisibleTime(retrieveTime + invisibleTime) + .receiptHandle(receiptHandle).build(); + } + + ReceiptHandle(final long startOffset, final long retrieveTime, final long invisibleTime, final long nextVisibleTime, + final int reviveQueueId, final String topic, final String brokerName, final int queueId, final long offset, + final String receiptHandle) { + this.startOffset = startOffset; + this.retrieveTime = retrieveTime; + this.invisibleTime = invisibleTime; + this.nextVisibleTime = nextVisibleTime; + this.reviveQueueId = reviveQueueId; + this.topic = topic; + this.brokerName = brokerName; + this.queueId = queueId; + this.offset = offset; + this.receiptHandle = receiptHandle; + } + + public static class ReceiptHandleBuilder { + private long startOffset; + private long retrieveTime; + private long invisibleTime; + private long nextVisibleTime; + private int reviveQueueId; + private String topic; + private String brokerName; + private int queueId; + private long offset; + private long commitLogOffset; + private String type; + private String receiptHandle; + + ReceiptHandleBuilder() { + } + + public ReceiptHandle.ReceiptHandleBuilder startOffset(final long startOffset) { + this.startOffset = startOffset; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder retrieveTime(final long retrieveTime) { + this.retrieveTime = retrieveTime; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder invisibleTime(final long invisibleTime) { + this.invisibleTime = invisibleTime; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder nextVisibleTime(final long nextVisibleTime) { + this.nextVisibleTime = nextVisibleTime; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder reviveQueueId(final int reviveQueueId) { + this.reviveQueueId = reviveQueueId; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder topic(final String topic) { + this.topic = topic; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder brokerName(final String brokerName) { + this.brokerName = brokerName; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder queueId(final int queueId) { + this.queueId = queueId; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder offset(final long offset) { + this.offset = offset; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder commitLogOffset(final long commitLogOffset) { + this.commitLogOffset = commitLogOffset; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder type(final String type) { + this.type = type; + return this; + } + + public ReceiptHandle.ReceiptHandleBuilder receiptHandle(final String receiptHandle) { + this.receiptHandle = receiptHandle; + return this; + } + + public ReceiptHandle build() { + return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.nextVisibleTime, this.reviveQueueId, this.topic, this.brokerName, this.queueId, this.offset, this.receiptHandle); + } + + @java.lang.Override + public java.lang.String toString() { + return "ReceiptHandle.ReceiptHandleBuilder(startOffset=" + this.startOffset + ", retrieveTime=" + this.retrieveTime + ", invisibleTime=" + this.invisibleTime + ", nextVisibleTime=" + this.nextVisibleTime + ", reviveQueueId=" + this.reviveQueueId + ", topic=" + this.topic + ", brokerName=" + this.brokerName + ", queueId=" + this.queueId + ", offset=" + this.offset + ", commitLogOffset=" + this.commitLogOffset + ", type=" + this.type + ", receiptHandle=" + this.receiptHandle + ")"; + } + } + + public static ReceiptHandle.ReceiptHandleBuilder builder() { + return new ReceiptHandle.ReceiptHandleBuilder(); + } + + public long getStartOffset() { + return this.startOffset; + } + + public long getRetrieveTime() { + return this.retrieveTime; + } + + public long getInvisibleTime() { + return this.invisibleTime; + } + + public long getNextVisibleTime() { + return this.nextVisibleTime; + } + + public int getReviveQueueId() { + return this.reviveQueueId; + } + + public String getTopic() { + return this.topic; + } + + public String getBrokerName() { + return this.brokerName; + } + + public int getQueueId() { + return this.queueId; + } + + public long getOffset() { + return this.offset; + } + + public String getReceiptHandle() { + return this.receiptHandle; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index c6ec938570..229e0a4daa 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc.common; +import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.ConsumeMessageType; import apache.rocketmq.v1.ConsumeModel; import apache.rocketmq.v1.ConsumePolicy; @@ -29,6 +30,7 @@ import apache.rocketmq.v1.FilterType; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessageType; +import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.ProducerData; import apache.rocketmq.v1.ReceiveMessageRequest; @@ -53,6 +55,7 @@ import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageAccessor; @@ -60,6 +63,8 @@ import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -143,6 +148,37 @@ public class Converter { return requestHeader; } + public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String receiptHandleStr = request.getReceiptHandle(); + ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + ackMessageRequestHeader.setConsumerGroup(groupName); + ackMessageRequestHeader.setTopic(topicName); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + return ackMessageRequestHeader; + } + + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String receiptHandleStr = request.getReceiptHandle(); + ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(topicName); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(handle.getInvisibleTime()); + return changeInvisibleTimeRequestHeader; + } + public static Map buildMessageProperty(Message message) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 9c5133b6fc..06dafea8e7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -54,6 +54,7 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; +import io.netty.channel.Channel; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -63,11 +64,12 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; @@ -107,7 +109,7 @@ public class LocalGrpcService implements GrpcForwardService { languageCode = LanguageCode.valueOf(language); HeartbeatData heartbeatData = Converter.buildHeartbeatData(request); - SimpleChannel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -200,11 +202,51 @@ public class LocalGrpcService implements GrpcForwardService { } @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return null; + Channel channel = channelManager.createChannel(); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + AckMessageRequestHeader requestHeader = Converter.buildAckMessageRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); + command.makeCustomHeaderToNet(); + + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand responseCommand = brokerController.getAckMessageProcessor() + .processRequest(channelHandlerContext, command); + AckMessageResponse.Builder builder = AckMessageResponse.newBuilder(); + if (null != responseCommand) { + builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + } else { + builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); + } + AckMessageResponse response = builder.build(); + future.complete(response); + } catch (Exception e) { + LOGGER.error("Exception raised when ack message", e); + } + return future; } @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - return null; + Channel channel = channelManager.createChannel(); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + + ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); + command.makeCustomHeaderToNet(); + + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() + .processRequest(channelHandlerContext, command); + NackMessageResponse response = NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())) + .build(); + future.complete(response); + } catch (Exception e) { + LOGGER.error("Exception raised while changeInvisibleTime", e); + future.completeExceptionally(e); + } + return future; } @Override From f07904a70acdc99fa2d79c458de9609f85356f8e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 11:51:31 +0800 Subject: [PATCH 035/338] [ISSUE #3949] Simplify Channels --- .../proxy/channel/ChannelManager.java | 11 +++++----- .../proxy/channel/InvocationChannel.java | 17 ++++++++++---- .../apache/rocketmq/proxy/common/Cleaner.java | 22 +++++++++++++++++++ .../channel/ReceiveMessageChannel.java | 21 +----------------- .../adapter/channel/SendMessageChannel.java | 22 +------------------ 5 files changed, 42 insertions(+), 51 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 53bf9e33c8..61910fb248 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.common.Cleaner; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,13 +102,12 @@ public class ChannelManager { Iterator> iterator = clientIdChannelMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); - if (!entry.getValue() - .isActive()) { + if (!entry.getValue().isActive()) { iterator.remove(); } else { - if (entry.getValue() instanceof SendMessageChannel) { - SendMessageChannel channel = (SendMessageChannel) entry.getValue(); - channel.cleanExpiredRequests(); + if (entry.getValue() instanceof Cleaner) { + Cleaner cleaner = (Cleaner) entry.getValue(); + cleaner.clean(); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java index 4c70cc74c8..23caa9e8e5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -23,21 +23,29 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.proxy.common.Cleaner; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.handler.ResponseHandler; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class InvocationChannel extends SimpleChannel { +public abstract class InvocationChannel extends SimpleChannel implements Cleaner { protected final ConcurrentMap> inFlightRequestMap; + protected final ResponseHandler handler; - public InvocationChannel(SimpleChannel simpleChannel) { - super(simpleChannel); + public InvocationChannel(ResponseHandler handler) { + super(ChannelManager.createSimpleChannelDirectly()); this.inFlightRequestMap = new ConcurrentHashMap<>(); + this.handler = handler; } @Override public ChannelFuture writeAndFlush(Object msg) { if (msg instanceof RemotingCommand) { RemotingCommand responseCommand = (RemotingCommand) msg; + InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); + if (null != context) { + handler.handle(responseCommand, context); + } inFlightRequestMap.remove(responseCommand.getOpaque()); } return super.writeAndFlush(msg); @@ -64,7 +72,8 @@ public class InvocationChannel extends SimpleChannel { inFlightRequestMap.remove(opaque); } - public void cleanExpiredRequests() { + @Override + public void clean() { Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); int count = 0; while (iterator.hasNext()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java new file mode 100644 index 0000000000..a02b08a913 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.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.proxy.common; + +public interface Cleaner { + void clean(); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java index acc280a73f..934b049b78 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java @@ -19,30 +19,11 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; -import io.netty.channel.ChannelFuture; -import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ReceiveMessageChannel extends InvocationChannel { - private final ReceiveMessageResponseHandler handler; - public ReceiveMessageChannel(ReceiveMessageResponseHandler handler) { - super(ChannelManager.createSimpleChannelDirectly()); - this.handler = handler; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - if (msg instanceof RemotingCommand) { - RemotingCommand responseCommand = (RemotingCommand) msg; - InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); - if (null != context) { - handler.handle(responseCommand, context); - } - } - return super.writeAndFlush(msg); + super(handler); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java index d0037d43fb..3eeb98f1ec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java @@ -19,31 +19,11 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; -import io.netty.channel.ChannelFuture; -import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class SendMessageChannel extends InvocationChannel { - private final SendMessageResponseHandler handler; - public SendMessageChannel(SendMessageResponseHandler handler) { - super(ChannelManager.createSimpleChannelDirectly()); - this.handler = handler; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - if (msg instanceof RemotingCommand) { - RemotingCommand responseCommand = (RemotingCommand) msg; - InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); - if (null != context) { - handler.handle(responseCommand, context); - } - } - - return super.writeAndFlush(msg); + super(handler); } } From 42ee31ec4df6145456bb6420fa7c5c858dc462e7 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 14:55:27 +0800 Subject: [PATCH 036/338] [ISSUE #3949] Implement ForwardMessageToDeadLetterQueue --- .../rocketmq/proxy/grpc/common/Converter.java | 19 ++++++++++++ .../proxy/grpc/service/LocalGrpcService.java | 29 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 229e0a4daa..bfc005d259 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -27,6 +27,7 @@ import apache.rocketmq.v1.DigestType; import apache.rocketmq.v1.Encoding; import apache.rocketmq.v1.FilterExpression; import apache.rocketmq.v1.FilterType; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessageType; @@ -65,6 +66,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -179,6 +181,23 @@ public class Converter { return changeInvisibleTimeRequestHeader; } + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( + ForwardMessageToDeadLetterQueueRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String receiptHandleStr = request.getReceiptHandle(); + ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); + consumerSendMsgBackRequestHeader.setOriginMsgId(topicName); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); + return consumerSendMsgBackRequestHeader; + } + public static Map buildMessageProperty(Message message) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 06dafea8e7..9169f191ee 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -66,10 +66,12 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; @@ -252,7 +254,32 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return null; + SimpleChannel channel = channelManager.createChannel(); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + + ConsumerSendMsgBackRequestHeader requestHeader = Converter.buildConsumerSendMsgBackRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + command.makeCustomHeaderToNet(); + + CompletableFuture future = new CompletableFuture<>(); + try { + CompletableFuture processorFuture = brokerController.getSendMessageProcessor() + .asyncProcessRequest(channelHandlerContext, command); + processorFuture.thenAccept(r -> { + ForwardMessageToDeadLetterQueueResponse.Builder builder = ForwardMessageToDeadLetterQueueResponse.newBuilder(); + if (null != r) { + builder.setCommon(ResponseBuilder.buildCommon(r.getCode(), r.getRemark())); + } else { + builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); + } + ForwardMessageToDeadLetterQueueResponse response = builder.build(); + future.complete(response); + }); + } catch (Exception e) { + LOGGER.error("Exception raised when forwardMessageToDeadLetterQueue", e); + future.completeExceptionally(e); + } + return future; } @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { From 89e0727b741113c572efe9c2b98feae231d23422 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 16 Mar 2022 15:27:09 +0800 Subject: [PATCH 037/338] [ISSUE #3949] receiveMessage for cluster mode; code refactor for queryRoute, queryAssignment, sendMessage --- .../connector/route/TopicRouteCache.java | 13 +- .../rocketmq/proxy/grpc/common/Converter.java | 19 +- .../proxy/grpc/common/ParameterConverter.java | 23 ++ .../proxy/grpc/common/ResponseBuilder.java | 22 +- .../proxy/grpc/common/ResponseHook.java | 22 ++ .../grpc/service/ClusterGrpcService.java | 96 ++++++-- .../grpc/service/cluster/BaseService.java | 6 +- .../grpc/service/cluster/ClientService.java | 107 +++++++++ ...ltPopResultResponseParameterConverter.java | 62 +++++ .../DefaultProducerMessageConverter.java | 30 +++ .../cluster/DefaultProducerQueueSelector.java | 79 ++++++ .../DefaultProducerRequestConverter.java | 31 +++ .../DefaultProducerResponseConverter.java | 43 ++++ .../DefaultReceiveMessageQueueSelector.java | 55 +++++ .../DefaultRouteAssignmentQueueSelector.java | 40 ++++ .../cluster/ProducerQueueSelector.java | 28 +++ .../grpc/service/cluster/ProducerService.java | 109 +++------ ....java => ReceiveMessageQueueSelector.java} | 15 +- .../cluster/ReceiveMessageService.java | 109 +++++++++ .../cluster/RouteAssignmentQueueSelector.java | 27 +++ .../grpc/service/cluster/RouteService.java | 90 ++++--- .../DefaultProducerQueueSelectorTest.java | 147 ++++++++++++ .../service/cluster/ProducerServiceTest.java | 226 ++++-------------- .../service/cluster/RouteServiceTest.java | 19 -- 24 files changed, 1045 insertions(+), 373 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ConsumerService.java => ReceiveMessageQueueSelector.java} (67%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index 5deb131383..752bb96b60 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -76,12 +76,23 @@ public class TopicRouteCache { return getMessageQueue(topic).getWriteSelector().selectOne(brokerName, queueId); } - public SelectableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey, SelectableMessageQueue last) throws Exception { + public SelectableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey) throws Exception { List writeQueues = getMessageQueue(topic).getWriteSelector().getQueues(); int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); return writeQueues.get(bucket); } + public SelectableMessageQueue selectReadBrokerByName(String topic, String brokerName) throws Exception { + return getMessageQueue(topic).getReadSelector().getQueueByBrokerName(brokerName); + } + + public SelectableMessageQueue selectOneReadBroker(String topic, SelectableMessageQueue last) throws Exception { + if (last == null) { + return getMessageQueue(topic).getReadSelector().selectOne(true); + } + return getMessageQueue(topic).getReadSelector().selectNextQueue(last); + } + protected static MessageQueueWrapper getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { MessageQueueWrapper res = topicCache.get(key); if (res.isEmptyCachedQueue()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index bfc005d259..8ffffcc597 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -363,18 +363,21 @@ public class Converter { for (SubscriptionEntry sub : subscriptionEntryList) { String topicName = Converter.getResourceNameWithNamespace(sub.getTopic()); FilterExpression filterExpression = sub.getExpression(); - String expression = filterExpression.getExpression(); - String expressionType = Converter.buildExpressionType(filterExpression.getType()); - try { - SubscriptionData subscriptionData = FilterAPI.build(topicName, expression, expressionType); - subscriptionDataSet.add(subscriptionData); - } catch (Exception e) { - throw new IllegalArgumentException("Build subscription failed when apply heartbeat", e); - } + subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); } return subscriptionDataSet; } + public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { + String expression = filterExpression.getExpression(); + String expressionType = Converter.buildExpressionType(filterExpression.getType()); + try { + return FilterAPI.build(topicName, expression, expressionType); + } catch (Exception e) { + throw new IllegalArgumentException("Build subscription failed when apply heartbeat", e); + } + } + public static int buildConsumeInitMode(ConsumePolicy policy) { switch (policy) { case PLAYBACK: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java new file mode 100644 index 0000000000..6e9ce1643c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java @@ -0,0 +1,23 @@ +/* + * 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.grpc.common; + +import io.grpc.Context; + +public interface ParameterConverter { + R convert(Context ctx, T parameter) throws Throwable; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index 11d347550c..ad519f4faa 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -18,13 +18,18 @@ package org.apache.rocketmq.proxy.grpc.common; import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.ResponseCommon; import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.ByteString; import com.google.rpc.Code; import com.google.rpc.Status; +import java.util.Map; import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -73,19 +78,6 @@ public class ResponseBuilder { .build(); } - public static SendMessageResponse buildSendMessageResponse(SendResult sendResult) { - if (sendResult.getSendStatus() != SendStatus.SEND_OK) { - return SendMessageResponse.newBuilder() - .setCommon(buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) - .build(); - } - return SendMessageResponse.newBuilder() - .setCommon(buildCommon(Code.OK, Code.OK.name())) - .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) - .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) - .build(); - } - public static Code buildCode(int responseCode) { Code code; switch (responseCode) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java new file mode 100644 index 0000000000..6af3052142 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.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.proxy.grpc.common; + +public interface ResponseHook { + + void beforeResponse(T request, R response, Throwable t); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 59a0df7f1c..e2f0caf569 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -49,13 +49,25 @@ import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; import apache.rocketmq.v1.ReportThreadStackTraceRequest; import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; +import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.slf4j.Logger; @@ -64,17 +76,28 @@ import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ConnectorManager forwardClientManager; + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread")); + + private final ChannelManager channelManager; + + private final ConnectorManager connectorManager; private final ProducerService producerService; + private final ReceiveMessageService receiveMessageService; private final RouteService routeService; + private final ClientService clientService; public ClusterGrpcService() { - this.forwardClientManager = new ConnectorManager(checkData -> { + this.channelManager = new ChannelManager(); + this.connectorManager = new ConnectorManager(checkData -> { }); - this.producerService = new ProducerService(forwardClientManager); - this.routeService = new RouteService(forwardClientManager); + this.receiveMessageService = new ReceiveMessageService(connectorManager); + this.producerService = new ProducerService(connectorManager); + this.routeService = new RouteService(connectorManager); + this.clientService = new ClientService(scheduledExecutorService); - this.appendStartAndShutdown(this.forwardClientManager); + this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); + this.appendStartAndShutdown(this.connectorManager); } @Override @@ -84,12 +107,18 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - return null; + this.clientService.heartbeat(ctx, request, channelManager); + return CompletableFuture.completedFuture(HeartbeatResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build()); } @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { - return null; + final HealthCheckResponse response = HealthCheckResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + return CompletableFuture.completedFuture(response); } @Override @@ -104,10 +133,11 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return null; + return this.receiveMessageService.receiveMessage(ctx, request); } - @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + @Override + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { return null; } @@ -121,7 +151,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return null; } - @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + @Override + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { return null; } @@ -133,8 +164,26 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return null; } - @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - return null; + @Override + public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { + CompletableFuture future = new CompletableFuture<>(); + String clientId = request.getClientId(); + + switch (request.getGroupCase()) { + case PRODUCER_GROUP: + Resource producerGroup = request.getProducerGroup(); + String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); + GrpcClientChannel.addClientObserver(this.channelManager, producerGroupName, clientId, future); + break; + case CONSUMER_GROUP: + Resource consumerGroup = request.getConsumerGroup(); + String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); + GrpcClientChannel.addClientObserver(this.channelManager, consumerGroupName, clientId, future); + break; + default: + break; + } + return future; } @Override public CompletableFuture reportThreadStackTrace(Context ctx, @@ -148,13 +197,30 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return null; } - @Override public CompletableFuture notifyClientTermination(Context ctx, + @Override + public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - return null; + this.clientService.unregister(ctx, request, channelManager); + return CompletableFuture.completedFuture(NotifyClientTerminationResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build()); } @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { return null; } + + private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { + + @Override + public void start() throws Exception { + + } + + @Override + public void shutdown() throws Exception { + scheduledExecutorService.shutdown(); + } + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index 9178a1cea7..87b42ce706 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -20,9 +20,9 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; public class BaseService { - protected final ConnectorManager clientManager; + protected final ConnectorManager connectorManager; - public BaseService(ConnectorManager clientManager) { - this.clientManager = clientManager; + public BaseService(ConnectorManager connectorManager) { + this.connectorManager = connectorManager; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java new file mode 100644 index 0000000000..44acde7df0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -0,0 +1,107 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.ConsumerData; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import io.grpc.Context; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClientService { + + private static final Logger log = LoggerFactory.getLogger(ClientService.class); + + private final ConsumerManager consumerManager = new ConsumerManager((event, group, args) -> { + }); + private final ProducerManager producerManager = new ProducerManager(); + + public ClientService(ScheduledExecutorService scheduledExecutorService) { + scheduledExecutorService.scheduleWithFixedDelay(this::scanNotActiveChannel, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); + } + + public void heartbeat(Context ctx, HeartbeatRequest request, ChannelManager channelManager) { + String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); + LanguageCode languageCode = LanguageCode.valueOf(language); + String clientId = request.getClientId(); + + if (request.hasProducerData()) { + String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + producerManager.registerProducer(producerGroup, clientChannelInfo); + } + + if (request.hasConsumerData()) { + ConsumerData consumerData = request.getConsumerData(); + String consumerGroup = Converter.getResourceNameWithNamespace(consumerData.getGroup()); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, consumerGroup, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + + consumerManager.registerConsumer( + consumerGroup, + clientChannelInfo, + Converter.buildConsumeType(consumerData.getConsumeType()), + Converter.buildMessageModel(consumerData.getConsumeModel()), + Converter.buildConsumeFromWhere(consumerData.getConsumePolicy()), + Converter.buildSubscriptionDataSet(consumerData.getSubscriptionsList()), + false + ); + } + } + + public void unregister(Context ctx, NotifyClientTerminationRequest request, ChannelManager channelManager) { + String clientId = request.getClientId(); + + if (request.hasProducerGroup()) { + String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerGroup()); + GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, producerGroup, clientId); + if (channel != null) { + producerManager.doChannelCloseEvent(producerGroup, channel); + } + } + + if (request.hasConsumerGroup()) { + String consumerGroup = Converter.getResourceNameWithNamespace(request.getConsumerGroup()); + GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); + if (channel != null) { + consumerManager.doChannelCloseEvent(consumerGroup, channel); + } + } + } + + private void scanNotActiveChannel() { + try { + this.consumerManager.scanNotActiveChannel(); + this.producerManager.scanNotActiveChannel(); + } catch (Exception e) { + log.error("error occurred when scan not active client channels.", e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java new file mode 100644 index 0000000000..7d960f85fa --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.ReceiveMessageResponse; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; + +public class DefaultPopResultResponseParameterConverter implements ParameterConverter { + + @Override + public ReceiveMessageResponse convert(Context ctx, PopResult result) throws Throwable { + PopStatus status = result.getPopStatus(); + switch (status) { + case FOUND: + break; + case POLLING_FULL: + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.RESOURCE_EXHAUSTED, "polling full")) + .build(); + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, "no new message")) + .build(); + } + + List messages = new ArrayList<>(); + for (MessageExt messageExt : result.getMsgFoundList()) { + messages.add(Converter.buildMessage(messageExt)); + } + + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .addAllMessages(messages) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java new file mode 100644 index 0000000000..841aea9330 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.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.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Message; +import io.grpc.Context; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; + +public class DefaultProducerMessageConverter implements ParameterConverter { + + @Override + public org.apache.rocketmq.common.message.Message convert(Context ctx, Message parameter) { + return Converter.buildMessage(parameter); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java new file mode 100644 index 0000000000..5b7122f1c8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java @@ -0,0 +1,79 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.SendMessageRequest; +import io.grpc.Context; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultProducerQueueSelector implements ProducerQueueSelector { + + private static final Logger log = LoggerFactory.getLogger(DefaultProducerQueueSelector.class); + protected final TopicRouteCache topicRouteCache; + + public DefaultProducerQueueSelector(TopicRouteCache topicRouteCache) { + this.topicRouteCache = topicRouteCache; + } + + @Override + public SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, + SendMessageRequestHeader requestHeader, + org.apache.rocketmq.common.message.Message message) { + try { + String topic = requestHeader.getTopic(); + String brokerName = ""; + if (request.hasPartition()) { + brokerName = request.getPartition().getBroker().getName(); + } + Integer queueId = requestHeader.getQueueId(); + String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + SelectableMessageQueue addressableMessageQueue; + if (!StringUtils.isBlank(brokerName) && queueId != null) { + // Grpc client sendSelect situation + addressableMessageQueue = selectTargetQueue(topic, brokerName, queueId); + } else if (shardingKey != null) { + // With shardingKey + addressableMessageQueue = selectOrderQueue(topic, shardingKey); + } else { + addressableMessageQueue = selectNormalQueue(topic); + } + return addressableMessageQueue; + } catch (Exception e) { + log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); + return null; + } + } + + protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { + return this.topicRouteCache.selectOneWriteQueue(topic, null); + } + + protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, + int queueId) throws Exception { + return this.topicRouteCache.selectOneWriteQueue(topic, brokerName, queueId); + } + + protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { + return this.topicRouteCache.selectOneWriteQueueByKey(topic, shardingKey); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java new file mode 100644 index 0000000000..cfe62ce7a2 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.SendMessageRequest; +import io.grpc.Context; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; + +public class DefaultProducerRequestConverter implements ParameterConverter { + + @Override + public SendMessageRequestHeader convert(Context ctx, SendMessageRequest parameter) { + return Converter.buildSendMessageRequestHeader(parameter); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java new file mode 100644 index 0000000000..db5095128f --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java @@ -0,0 +1,43 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.SendMessageResponse; +import com.google.rpc.Code; +import io.grpc.Context; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; + +public class DefaultProducerResponseConverter implements ParameterConverter { + + @Override + public SendMessageResponse convert(Context ctx, SendResult sendResult) { + if (sendResult.getSendStatus() != SendStatus.SEND_OK) { + return SendMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) + .build(); + } + return SendMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) + .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java new file mode 100644 index 0000000000..df59b5e12b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java @@ -0,0 +1,55 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.ReceiveMessageRequest; +import io.grpc.Context; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; + +public class DefaultReceiveMessageQueueSelector implements ReceiveMessageQueueSelector { + + private final TopicRouteCache topicRouteCache; + + public DefaultReceiveMessageQueueSelector(TopicRouteCache topicRouteCache) { + this.topicRouteCache = topicRouteCache; + } + + @Override + public SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader) { + SelectableMessageQueue messageQueue = null; + try { + String topic = requestHeader.getTopic(); + + if (request.hasPartition() && request.getPartition().hasBroker()) { + String brokerName = request.getPartition().getBroker().getName(); + if (StringUtils.isNotBlank(brokerName)) { + messageQueue = topicRouteCache.selectReadBrokerByName(topic, brokerName); + } + } + + if (messageQueue == null) { + messageQueue = topicRouteCache.selectOneReadBroker(topic, null); + } + return messageQueue; + } catch (Throwable t) { + return null; + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java new file mode 100644 index 0000000000..e112853b54 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.QueryAssignmentRequest; +import io.grpc.Context; +import java.util.List; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.common.Converter; + +public class DefaultRouteAssignmentQueueSelector implements RouteAssignmentQueueSelector { + + private final TopicRouteCache topicRouteCache; + + public DefaultRouteAssignmentQueueSelector(TopicRouteCache topicRouteCache) { + this.topicRouteCache = topicRouteCache; + } + + @Override + public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { + MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java new file mode 100644 index 0000000000..ae4619db88 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java @@ -0,0 +1,28 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.SendMessageRequest; +import io.grpc.Context; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; + +public interface ProducerQueueSelector { + + SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, + SendMessageRequestHeader requestHeader, org.apache.rocketmq.common.message.Message message); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 5da401fba1..7478e2f3ed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -16,22 +16,20 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.Message; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import io.grpc.Context; import java.util.concurrent.CompletableFuture; -import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.common.ResponseHook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,83 +37,54 @@ public class ProducerService extends BaseService { private static final Logger log = LoggerFactory.getLogger(ProducerService.class); - private volatile ProducerServiceHook producerServiceHook = null; - private volatile MessageQueueSelector messageQueueSelector = new DefaultMessageQueueSelector(); + private volatile ParameterConverter parameterConverter; + private volatile ParameterConverter messageConverter; + private volatile ParameterConverter responseConverter; + private volatile ProducerQueueSelector messageQueueSelector; + private volatile ResponseHook producerServiceHook = null; - public ProducerService(ConnectorManager clientManager) { - super(clientManager); + public ProducerService(ConnectorManager connectorManager) { + super(connectorManager); + + parameterConverter = new DefaultProducerRequestConverter(); + messageConverter = new DefaultProducerMessageConverter(); + responseConverter = new DefaultProducerResponseConverter(); + messageQueueSelector = new DefaultProducerQueueSelector(this.connectorManager.getTopicRouteCache()); } - public interface MessageQueueSelector { - SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, - org.apache.rocketmq.common.message.Message message); + public void setParameterConverter( + ParameterConverter parameterConverter) { + this.parameterConverter = parameterConverter; } - public class DefaultMessageQueueSelector implements MessageQueueSelector { - - @Override - public SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, - org.apache.rocketmq.common.message.Message message) { - try { - String topic = requestHeader.getTopic(); - String brokerName = ""; - if (request.hasPartition()) { - brokerName = request.getPartition().getBroker().getName(); - } - Integer queueId = requestHeader.getQueueId(); - String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); - SelectableMessageQueue addressableMessageQueue; - if (!StringUtils.isBlank(brokerName) && queueId != null) { - // Grpc client sendSelect situation - addressableMessageQueue = selectTargetQueue(topic, brokerName, queueId); - } else if (shardingKey != null) { - // With shardingKey - addressableMessageQueue = selectOrderQueue(topic, shardingKey); - } else { - addressableMessageQueue = selectNormalQueue(topic); - } - return addressableMessageQueue; - } catch (Exception e) { - log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); - return null; - } - } - - protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { - return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, null); - } - - protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { - return clientManager.getTopicRouteCache().selectOneWriteQueue(topic, brokerName, queueId); - } - - protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { - return clientManager.getTopicRouteCache().selectOneWriteQueueByKey(topic, shardingKey, null); - } + public void setMessageConverter( + ParameterConverter messageConverter) { + this.messageConverter = messageConverter; } - public interface ProducerServiceHook { - - void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader); - - void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, Message msg, SendMessageRequestHeader requestHeader, - SendResult sendResult); + public void setResponseConverter(ParameterConverter responseConverter) { + this.responseConverter = responseConverter; } - public void setProducerServiceHook(ProducerServiceHook hook) { - this.producerServiceHook = hook; + public void setProducerServiceHook(ResponseHook producerServiceHook) { + this.producerServiceHook = producerServiceHook; } - public void setMessageQueueSelector(MessageQueueSelector messageQueueSelector) { + public void setMessageQueueSelector(ProducerQueueSelector messageQueueSelector) { this.messageQueueSelector = messageQueueSelector; } public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - org.apache.rocketmq.common.message.Message message = Converter.buildMessage(request.getMessage()); CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (producerServiceHook != null) { + producerServiceHook.beforeResponse(request, response, throwable); + } + }); try { - SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); + org.apache.rocketmq.common.message.Message message = messageConverter.convert(ctx, request.getMessage()); + SendMessageRequestHeader requestHeader = this.parameterConverter.convert(ctx, request); SelectableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); @@ -124,10 +93,7 @@ public class ProducerService extends BaseService { "no writeable topic route for topic " + topic); } - if (producerServiceHook != null) { - producerServiceHook.beforeSend(ctx, addressableMessageQueue, message, requestHeader); - } - CompletableFuture sendResultCompletableFuture = this.clientManager.getForwardProducer().sendMessage( + CompletableFuture sendResultCompletableFuture = this.connectorManager.getForwardProducer().sendMessage( addressableMessageQueue.getBrokerAddr(), addressableMessageQueue.getBrokerName(), message, @@ -136,10 +102,11 @@ public class ProducerService extends BaseService { ); sendResultCompletableFuture .thenAccept(result -> { - if (producerServiceHook != null) { - producerServiceHook.afterSend(ctx, addressableMessageQueue, message, requestHeader, result); + try { + future.complete(this.responseConverter.convert(ctx, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); } - future.complete(ResponseBuilder.buildSendMessageResponse(result)); }) .exceptionally(e -> { future.completeExceptionally(e); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java similarity index 67% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java index 9f091f9fb9..c671709cff 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java @@ -17,18 +17,11 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -public class ConsumerService extends BaseService { +public interface ReceiveMessageQueueSelector { - public ConsumerService(ConnectorManager clientManager) { - super(clientManager); - } - - public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return null; - } + SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java new file mode 100644 index 0000000000..85c0418cf8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java @@ -0,0 +1,109 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; +import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseHook; + +public class ReceiveMessageService extends BaseService { + + private final ForwardReadConsumer readConsumer; + private final ForwardWriteConsumer writeConsumer; + private final TopicRouteCache topicRouteCache; + + private ParameterConverter popResultResponseParameterConverter; + private ReceiveMessageQueueSelector receiveMessageQueueSelector; + private ResponseHook receiveMessageHook = null; + + private ResponseHook ackMessageHook = null; + + public ReceiveMessageService(ConnectorManager connectorManager) { + super(connectorManager); + this.readConsumer = connectorManager.getForwardReadConsumer(); + this.writeConsumer = connectorManager.getForwardWriteConsumer(); + this.topicRouteCache = connectorManager.getTopicRouteCache(); + + this.popResultResponseParameterConverter = new DefaultPopResultResponseParameterConverter(); + this.receiveMessageQueueSelector = new DefaultReceiveMessageQueueSelector(connectorManager.getTopicRouteCache()); + } + + public void setPopResultResponseParameterConverter( + ParameterConverter popResultResponseParameterConverter) { + this.popResultResponseParameterConverter = popResultResponseParameterConverter; + } + + public void setReceiveMessageQueueSelector(ReceiveMessageQueueSelector receiveMessageQueueSelector) { + this.receiveMessageQueueSelector = receiveMessageQueueSelector; + } + + public void setReceiveMessageHook(ResponseHook receiveMessageHook) { + this.receiveMessageHook = receiveMessageHook; + } + + public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(request, response, throwable); + } + }); + try { + long timeRemaining = Context.current() + .getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + + PopMessageRequestHeader requestHeader = Converter.buildPopMessageRequestHeader(request, pollTime); + SelectableMessageQueue messageQueue = this.receiveMessageQueueSelector.select(ctx, request, requestHeader); + + CompletableFuture popResultFuture = this.readConsumer.popMessage( + messageQueue.getBrokerAddr(), + messageQueue.getBrokerName(), + requestHeader, + pollTime); + popResultFuture.thenAccept(result -> { + try { + future.complete(popResultResponseParameterConverter.convert(ctx, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java new file mode 100644 index 0000000000..ecdfd63539 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.QueryAssignmentRequest; +import io.grpc.Context; +import java.util.List; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; + +public interface RouteAssignmentQueueSelector { + + List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 3032458311..2b4a34fc3b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -39,73 +39,68 @@ import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.common.ResponseHook; public class RouteService extends BaseService { - private volatile RouteAssignmentQueueSelector assignmentQueueSelector = new DefaultRouteAssignmentQueueSelector(); - private volatile QueryRouteHook queryRouteHook = null; - private volatile QueryAssignmentHook queryAssignmentHook = null; + private volatile ParameterConverter queryRouteEndpointConverter; + private volatile ResponseHook queryRouteHook = null; - public RouteService(ConnectorManager clientManager) { - super(clientManager); + private volatile ParameterConverter queryAssignmentEndpointConverter; + private volatile RouteAssignmentQueueSelector assignmentQueueSelector; + private volatile ResponseHook queryAssignmentHook = null; + + public RouteService(ConnectorManager connectorManager) { + super(connectorManager); + + queryRouteEndpointConverter = (ctx, parameter) -> parameter; + queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; + assignmentQueueSelector = new DefaultRouteAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); } - public interface QueryRouteHook { - QueryRouteResponse beforeResponse(Context ctx, QueryRouteRequest request, QueryRouteResponse response); + public void setQueryRouteEndpointConverter(ParameterConverter queryRouteEndpointConverter) { + this.queryRouteEndpointConverter = queryRouteEndpointConverter; } - public interface QueryAssignmentHook { - QueryAssignmentResponse beforeResponse(Context ctx, QueryAssignmentRequest request, - QueryAssignmentResponse response); - } - - public interface RouteAssignmentQueueSelector { - List getAssignment(QueryAssignmentRequest request) throws Exception; - } - - public class DefaultRouteAssignmentQueueSelector implements RouteAssignmentQueueSelector { - - @Override - public List getAssignment(QueryAssignmentRequest request) throws Exception { - MessageQueueWrapper messageQueueWrapper = clientManager.getTopicRouteCache() - .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); - return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); - } - } - - public void setQueryRouteHook(QueryRouteHook queryRouteHook) { + public void setQueryRouteHook(ResponseHook queryRouteHook) { this.queryRouteHook = queryRouteHook; } + public void setQueryAssignmentEndpointConverter( + ParameterConverter queryAssignmentEndpointConverter) { + this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; + } + public void setAssignmentQueueSelector(RouteAssignmentQueueSelector assignmentQueueSelector) { this.assignmentQueueSelector = assignmentQueueSelector; } - public void setQueryAssignmentHook(QueryAssignmentHook queryAssignmentHook) { + public void setQueryAssignmentHook( + ResponseHook queryAssignmentHook) { this.queryAssignmentHook = queryAssignmentHook; } public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { CompletableFuture future = new CompletableFuture<>(); - CompletableFuture resFuture = future.thenApply(r -> { - if (this.queryRouteHook != null) { - return this.queryRouteHook.beforeResponse(ctx, request, r); + future.whenComplete((response, throwable) -> { + if (queryRouteHook != null) { + queryRouteHook.beforeResponse(request, response, throwable); } - return r; }); try { - Endpoints resEndpoints = request.getEndpoints(); - if (resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); + if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); - return resFuture; + return future; } - MessageQueueWrapper messageQueueWrapper = this.clientManager.getTopicRouteCache() + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); @@ -134,7 +129,7 @@ public class RouteService extends BaseService { future.completeExceptionally(t); } } - return resFuture; + return future; } protected static List genPartitionFromQueueData(QueueData queueData, Resource topic, Broker broker) { @@ -172,24 +167,24 @@ public class RouteService extends BaseService { public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { CompletableFuture future = new CompletableFuture<>(); - CompletableFuture resFuture = future.thenApply(r -> { - if (this.queryAssignmentHook != null) { - return this.queryAssignmentHook.beforeResponse(ctx, request, r); + future.whenComplete((response, throwable) -> { + if (queryAssignmentHook != null) { + queryAssignmentHook.beforeResponse(request, response, throwable); } - return r; }); + try { - Endpoints resEndpoints = request.getEndpoints(); - if (resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); + if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); - return resFuture; + return future; } List assignments = new ArrayList<>(); - List messageQueueList = this.assignmentQueueSelector.getAssignment(request); + List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); for (SelectableMessageQueue messageQueue : messageQueueList) { Broker broker = Broker.newBuilder() @@ -213,13 +208,10 @@ public class RouteService extends BaseService { .addAllAssignments(assignments) .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .build(); - if (this.queryAssignmentHook != null) { - this.queryAssignmentHook.beforeResponse(ctx, request, response); - } future.complete(response); } catch (Throwable t) { future.completeExceptionally(t); } - return resFuture; + return future; } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java new file mode 100644 index 0000000000..99f662d956 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java @@ -0,0 +1,147 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.ByteString; +import io.grpc.Context; +import java.nio.charset.StandardCharsets; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.when; + +public class DefaultProducerQueueSelectorTest extends BaseServiceTest { + + private final DefaultProducerRequestConverter requestConverter = new DefaultProducerRequestConverter(); + private final DefaultProducerMessageConverter messageConverter = new DefaultProducerMessageConverter(); + + @Override + public void beforeEach() throws Throwable { + SelectableMessageQueue queue = new SelectableMessageQueue( + new MessageQueue("topic", "selectOrderQueue", 0), + "selectOrderQueueAddr"); + when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString())) + .thenReturn(queue); + + queue = new SelectableMessageQueue( + new MessageQueue("topic", "selectTargetQueue", 0), + "selectTargetQueueAddr"); + when(topicRouteCache.selectOneWriteQueue(anyString(), anyString(), anyInt())) + .thenReturn(queue); + + queue = new SelectableMessageQueue( + new MessageQueue("topic", "selectNormalQueue", 0), + "selectNormalQueueAddr"); + when(topicRouteCache.selectOneWriteQueue(anyString(), isNull())) + .thenReturn(queue); + } + + @Test + public void testSendOrderMessageWithShardingKey() { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build(); + ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, + requestConverter.convert(Context.current(), request), + messageConverter.convert(Context.current(), request.getMessage())); + + assertEquals("selectOrderQueue", queue.getBrokerName()); + assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); + } + + @Test + public void selectWithShardingKey() { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build(); + ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, + requestConverter.convert(Context.current(), request), + messageConverter.convert(Context.current(), request.getMessage())); + + assertEquals("selectOrderQueue", queue.getBrokerName()); + assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); + } + + @Test + public void selectNormalQueue() { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build(); + ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, + requestConverter.convert(Context.current(), request), + messageConverter.convert(Context.current(), request.getMessage())); + + assertEquals("selectNormalQueue", queue.getBrokerName()); + assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); + } + + @Test + public void selectTargetQueue() { + SendMessageRequest request = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .setPartition(Partition.newBuilder() + .setBroker(Broker.newBuilder() + .setName("brokerName") + .build()) + .build()) + .build(); + ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, + requestConverter.convert(Context.current(), request), + messageConverter.convert(Context.current(), request.getMessage())); + + assertEquals("selectTargetQueue", queue.getBrokerName()); + assertEquals("selectTargetQueueAddr", queue.getBrokerAddr()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 90a9a3e6ca..4f3d17ff1b 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -16,9 +16,7 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Broker; import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; @@ -29,12 +27,9 @@ import io.grpc.Context; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; @@ -46,37 +41,31 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; public class ProducerServiceTest extends BaseServiceTest { + private static final SendMessageRequest REQUEST = SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId("msgId") + .build()) + .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) + .build()) + .build(); + @Override public void beforeEach() throws Throwable { - SelectableMessageQueue queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectOrderQueue", 0), - "selectOrderQueueAddr"); - when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString(), isNull())) - .thenReturn(queue); - - queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectTargetQueue", 0), - "selectTargetQueueAddr"); - when(topicRouteCache.selectOneWriteQueue(anyString(), anyString(), anyInt())) - .thenReturn(queue); - - queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectNormalQueue", 0), - "selectNormalQueueAddr"); - when(topicRouteCache.selectOneWriteQueue(anyString(), isNull())) - .thenReturn(queue); } @Test - public void testSendOrderMessageWithShardingKey() { + public void testSendMessage() { CompletableFuture sendResultFuture = new CompletableFuture<>(); when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) .thenReturn(sendResultFuture); @@ -84,155 +73,15 @@ public class ProducerServiceTest extends BaseServiceTest { 1L, "txId", "offsetMsgId", "regionId")); ProducerService producerService = new ProducerService(this.clientManager); + producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> + new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); - AtomicReference selectQueueRef = new AtomicReference<>(); - AtomicReference messageRef = new AtomicReference<>(); - producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { - @Override - public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { - selectQueueRef.set(addressableMessageQueue); - } - - @Override - public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, - SendResult sendResult) { - - } - }); - - CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build()); - + CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); try { SendMessageResponse response = future.get(); assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); assertEquals("msgId", response.getMessageId()); - assertEquals("selectOrderQueue", selectQueueRef.get().getBrokerName()); - assertEquals("selectOrderQueueAddr", selectQueueRef.get().getBrokerAddr()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testSendNormalMessage() { - CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) - .thenReturn(sendResultFuture); - sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), - 1L, "txId", "offsetMsgId", "regionId")); - - ProducerService producerService = new ProducerService(this.clientManager); - - AtomicReference selectQueueRef = new AtomicReference<>(); - AtomicReference messageRef = new AtomicReference<>(); - producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { - @Override - public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { - selectQueueRef.set(addressableMessageQueue); - } - - @Override - public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, - SendResult sendResult) { - - } - }); - - CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build()); - - try { - SendMessageResponse response = future.get(); - - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals("msgId", response.getMessageId()); - assertEquals("selectNormalQueue", selectQueueRef.get().getBrokerName()); - assertEquals("selectNormalQueueAddr", selectQueueRef.get().getBrokerAddr()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testSendOrderMessageSelectQueue() { - CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) - .thenReturn(sendResultFuture); - sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), - 1L, "txId", "offsetMsgId", "regionId")); - - ProducerService producerService = new ProducerService(this.clientManager); - - AtomicReference selectQueueRef = new AtomicReference<>(); - AtomicReference messageRef = new AtomicReference<>(); - producerService.setProducerServiceHook(new ProducerService.ProducerServiceHook() { - @Override - public void beforeSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader) { - selectQueueRef.set(addressableMessageQueue); - } - - @Override - public void afterSend(Context ctx, SelectableMessageQueue addressableMessageQueue, - org.apache.rocketmq.common.message.Message msg, SendMessageRequestHeader requestHeader, - SendResult sendResult) { - - } - }); - - CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId("msgId") - .setPartitionId(1) - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .setPartition(Partition.newBuilder() - .setBroker(Broker.newBuilder() - .setName("brokerName") - .build()) - .build()) - .build()); - - try { - SendMessageResponse response = future.get(); - - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals("msgId", response.getMessageId()); - assertEquals("selectTargetQueue", selectQueueRef.get().getBrokerName()); - assertEquals("selectTargetQueueAddr", selectQueueRef.get().getBrokerAddr()); } catch (Exception e) { assertNull(e); } @@ -264,7 +113,7 @@ public class ProducerServiceTest extends BaseServiceTest { assertNotNull(e); assertTrue(e instanceof ExecutionException); assertTrue(e.getCause() instanceof ProxyException); - assertEquals(ProxyResponseCode.NO_TOPIC_ROUTE, ((ProxyException)e.getCause()).getCode()); + assertEquals(ProxyResponseCode.NO_TOPIC_ROUTE, ((ProxyException) e.getCause()).getCode()); } } @@ -278,19 +127,34 @@ public class ProducerServiceTest extends BaseServiceTest { sendResultFuture.completeExceptionally(ex); ProducerService producerService = new ProducerService(this.clientManager); + producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> + new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); - CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build()); + CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); + + try { + SendMessageResponse response = future.get(); + assertNull(response); + } catch (Exception e) { + assertNotNull(e); + assertTrue(e instanceof ExecutionException); + assertSame(ex, e.getCause()); + } + } + + @Test + public void testSendMessageWithErrorThrow() { + RuntimeException ex = new RuntimeException(); + + ProducerService producerService = new ProducerService(this.clientManager); + producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> { + throw ex; + }); + producerService.setProducerServiceHook((request, response, t) -> { + assertSame(ex, t); + }); + + CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); try { SendMessageResponse response = future.get(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 458dcb32b6..03a0439302 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -128,25 +128,6 @@ public class RouteServiceTest extends BaseServiceTest { } } - @Test - public void testQueryRouteHook() { - RouteService routeService = new RouteService(this.clientManager); - - routeService.setQueryRouteHook((ctx, request, response) -> QueryRouteResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.NOT_FOUND, Code.NOT_FOUND.name())) - .build()); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .build()); - - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } - } - @Test public void testQueryAssignmentInvalidEndpoints() { RouteService routeService = new RouteService(this.clientManager); From c456ea78839e402923e038c6ca526d8ef26d1be7 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 16:05:41 +0800 Subject: [PATCH 038/338] [ISSUE #3949] Implement pollCommand --- .../proxy/channel/ChannelManager.java | 12 +++++ .../adapter/channel/GrpcClientChannel.java | 26 +++------- .../proxy/grpc/service/LocalGrpcService.java | 50 +++++++++++++++++-- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 61910fb248..54a54f32be 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -20,9 +20,11 @@ package org.apache.rocketmq.proxy.channel; import com.google.common.base.Strings; import io.grpc.Context; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -34,6 +36,7 @@ import org.slf4j.LoggerFactory; public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); + private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { return createChannel(anonymousChannelId()); @@ -70,6 +73,10 @@ public class ChannelManager { return clazz.cast(channel); } + public void setChannel(String clientId, T channel) { + clientIdChannelMap.put(clientId, channel); + } + public T removeChannel(String clientId, Class clazz) { SimpleChannel channel = clientIdChannelMap.remove(clientId); if (channel == null) { @@ -94,6 +101,11 @@ public class ChannelManager { return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds()); } + public void addGroupClientId(String group, String clientId) { + groupClientIdMap.computeIfAbsent(group, k -> new CopyOnWriteArrayList<>()) + .add(clientId); + } + /** * Scan and remove inactive mocking channels; Scan and clean expired requests; */ diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index de8bfa906a..d62c5f80b0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -18,46 +18,32 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.PollCommandResponse; import io.netty.channel.ChannelFuture; -import java.util.List; -import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; public class GrpcClientChannel extends SimpleChannel { - - private static final Map/* clientId */> GROUP_CLIENT_IDS = new ConcurrentHashMap<>(); - private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); - public GrpcClientChannel() { + private GrpcClientChannel() { super(ChannelManager.createSimpleChannelDirectly()); } + public void addClientObserver(CompletableFuture future) { + this.pollCommandResponseFutureRef.set(future); + } + public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), GrpcClientChannel::new, GrpcClientChannel.class); - GROUP_CLIENT_IDS.compute(group, (groupKey, clientIds) -> { - if (clientIds == null) { - clientIds = new CopyOnWriteArrayList<>(); - } - clientIds.add(clientId); - return clientIds; - }); + channelManager.addGroupClientId(group, clientId); return channel; } - public static void addClientObserver(ChannelManager channelManager, String group, String clientId, CompletableFuture future) { - GrpcClientChannel channel = getChannel(channelManager, group, clientId); - channel.pollCommandResponseFutureRef.set(future); - } - public static GrpcClientChannel getChannel(ChannelManager channelManager, String group, String clientId) { return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannel.class); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 9169f191ee..c5bd4658d6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -50,6 +50,7 @@ import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; import apache.rocketmq.v1.ReportThreadStackTraceRequest; import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; @@ -75,6 +76,7 @@ import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; @@ -111,7 +113,24 @@ public class LocalGrpcService implements GrpcForwardService { languageCode = LanguageCode.valueOf(language); HeartbeatData heartbeatData = Converter.buildHeartbeatData(request); - Channel channel = channelManager.createChannel(); + CompletableFuture future = new CompletableFuture<>(); + String groupName; + switch (request.getClientDataCase()) { + case PRODUCER_DATA: { + groupName = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); + break; + } + case CONSUMER_DATA: { + groupName = Converter.getResourceNameWithNamespace(request.getConsumerData().getGroup()); + break; + } + default: { + future.completeExceptionally(new IllegalArgumentException("Wrong client data type")); + return future; + } + } + + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, request.getClientId()); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -122,7 +141,8 @@ public class LocalGrpcService implements GrpcForwardService { RemotingCommand response = this.brokerController.getClientManageProcessor() .heartBeat(simpleChannelHandlerContext, command); HeartbeatResponse heartbeatResponse = ResponseBuilder.buildHeartbeatResponse(response); - return CompletableFuture.completedFuture(heartbeatResponse); + future.complete(heartbeatResponse); + return future; } @Override @@ -282,7 +302,8 @@ public class LocalGrpcService implements GrpcForwardService { return future; } - @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + @Override + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { return null; } @@ -295,7 +316,25 @@ public class LocalGrpcService implements GrpcForwardService { } @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - return null; + String clientId = request.getClientId(); + CompletableFuture future = new CompletableFuture<>(); + switch (request.getGroupCase()) { + case PRODUCER_GROUP: + Resource producerGroup = request.getProducerGroup(); + String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); + GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); + producerChannel.addClientObserver(future); + break; + case CONSUMER_GROUP: + Resource consumerGroup = request.getConsumerGroup(); + String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); + GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); + consumerChannel.addClientObserver(future); + break; + default: + break; + } + return future; } @Override public CompletableFuture reportThreadStackTrace(Context ctx, @@ -303,7 +342,8 @@ public class LocalGrpcService implements GrpcForwardService { return null; } - @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, + @Override + public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { return null; } From 67440ebe27f5bc6cd43642467e023ee200b5dfc6 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 16 Mar 2022 16:57:13 +0800 Subject: [PATCH 039/338] [ISSUE #3949] pollCommand for cluster mode --- .../proxy/grpc/service/ClusterGrpcService.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index e2f0caf569..0769c6be09 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -31,6 +31,7 @@ import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NoopCommand; import apache.rocketmq.v1.NotifyClientTerminationRequest; import apache.rocketmq.v1.NotifyClientTerminationResponse; import apache.rocketmq.v1.PollCommandRequest; @@ -168,17 +169,28 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { CompletableFuture future = new CompletableFuture<>(); String clientId = request.getClientId(); + PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand(NoopCommand.newBuilder().build()).build(); switch (request.getGroupCase()) { case PRODUCER_GROUP: Resource producerGroup = request.getProducerGroup(); String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); - GrpcClientChannel.addClientObserver(this.channelManager, producerGroupName, clientId, future); + GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(this.channelManager, producerGroupName, clientId); + if (producerChannel == null) { + future.complete(noopCommandResponse); + } else { + producerChannel.addClientObserver(future); + } break; case CONSUMER_GROUP: Resource consumerGroup = request.getConsumerGroup(); String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); - GrpcClientChannel.addClientObserver(this.channelManager, consumerGroupName, clientId, future); + GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(this.channelManager, consumerGroupName, clientId); + if (consumerChannel == null) { + future.complete(noopCommandResponse); + } else { + consumerChannel.addClientObserver(future); + } break; default: break; From 5cbb01e3736ccd545b799327907722d1bc2d80e6 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 16 Mar 2022 17:12:20 +0800 Subject: [PATCH 040/338] [ISSUE #3949] Implement Local transaction module --- .../rocketmq/broker/BrokerController.java | 10 ++++- .../connector/transaction/TransactionId.java | 6 +-- .../adapter/channel/GrpcClientChannel.java | 39 +++++++++++++++++ .../rocketmq/proxy/grpc/common/Converter.java | 42 +++++++++++++++++++ .../proxy/grpc/service/LocalGrpcService.java | 39 ++++++++++++++++- 5 files changed, 130 insertions(+), 6 deletions(-) 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 44a4e902dd..7bf9cdcd9c 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -185,6 +185,7 @@ public class BrokerController { protected final Broker2Client broker2Client; protected final SubscriptionGroupManager subscriptionGroupManager; protected final ConsumerIdsChangeListener consumerIdsChangeListener; + protected final EndTransactionProcessor endTransactionProcessor; private final RebalanceLockManager rebalanceLockManager = new RebalanceLockManager(); protected BrokerOuterAPI brokerOuterAPI; protected ScheduledExecutorService scheduledExecutorService; @@ -317,6 +318,7 @@ public class BrokerController { this.queryAssignmentProcessor = new QueryAssignmentProcessor(this); this.clientManageProcessor = new ClientManageProcessor(this); this.slaveSynchronize = new SlaveSynchronize(this); + this.endTransactionProcessor = new EndTransactionProcessor(this); this.sendThreadPoolQueue = new LinkedBlockingQueue(this.brokerConfig.getSendThreadPoolQueueCapacity()); this.putThreadPoolQueue = new LinkedBlockingQueue(this.brokerConfig.getPutThreadPoolQueueCapacity()); @@ -1002,8 +1004,8 @@ public class BrokerController { /** * EndTransactionProcessor */ - this.remotingServer.registerProcessor(RequestCode.END_TRANSACTION, new EndTransactionProcessor(this), this.endTransactionExecutor); - this.fastRemotingServer.registerProcessor(RequestCode.END_TRANSACTION, new EndTransactionProcessor(this), this.endTransactionExecutor); + this.remotingServer.registerProcessor(RequestCode.END_TRANSACTION, endTransactionProcessor, this.endTransactionExecutor); + this.fastRemotingServer.registerProcessor(RequestCode.END_TRANSACTION, endTransactionProcessor, this.endTransactionExecutor); /* * Default @@ -2104,6 +2106,10 @@ public class BrokerController { return brokerPreOnlineService; } + public EndTransactionProcessor getEndTransactionProcessor() { + return endTransactionProcessor; + } + public boolean isScheduleServiceStart() { return isScheduleServiceStart; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index 63eb8b3f08..c04cb82bb3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -91,8 +91,8 @@ public class TransactionId { .build(); } - public static TransactionId genFromGatewayTransactionId(String gatewayTransactionId) throws UnknownHostException { - ByteBuffer byteBuffer = ByteBuffer.wrap(UtilAll.string2bytes(gatewayTransactionId)); + public static TransactionId decode(String transactionId) throws UnknownHostException { + ByteBuffer byteBuffer = ByteBuffer.wrap(UtilAll.string2bytes(transactionId)); byte[] ip = new byte[4]; byteBuffer.get(ip); @@ -111,7 +111,7 @@ public class TransactionId { .brokerTransactionId(new String(orgTransactionIdByte, StandardCharsets.UTF_8)) .commitLogOffset(commitLogOffset) .tranStateTableOffset(tranStateTableOffset) - .gatewayTransactionId(gatewayTransactionId) + .gatewayTransactionId(transactionId) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index d62c5f80b0..dfc8faa859 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -17,11 +17,19 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; import io.netty.channel.ChannelFuture; +import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); @@ -56,9 +64,40 @@ public class GrpcClientChannel extends SimpleChannel { return group + "@" + clientId; } + /** + * Write response to corresponding remote client + * + * @param msg Target write object, {@link RemotingCommand} or {@link PollCommandResponse} + * @return Always success {@link ChannelFuture} + *

+ * Case {@link RequestCode#CHECK_TRANSACTION_STATE} + * @see org.apache.rocketmq.broker.client.net.Broker2Client#checkProducerTransactionState + */ @Override public ChannelFuture writeAndFlush(Object msg) { CompletableFuture future = pollCommandResponseFutureRef.get(); + if (msg instanceof RemotingCommand) { + RemotingCommand command = (RemotingCommand) msg; + try { + switch (command.getCode()) { + case RequestCode.CHECK_TRANSACTION_STATE: { + final CheckTransactionStateRequestHeader requestHeader = + (CheckTransactionStateRequestHeader) command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); + RecoverOrphanedTransactionCommand recoverOrphanedTransactionCommand = RecoverOrphanedTransactionCommand.newBuilder() + .setTransactionId(requestHeader.getTransactionId()) + .setOrphanedTransactionalMessage(Converter.buildMessage(messageExt)) + .build(); + future.complete(PollCommandResponse.newBuilder() + .setRecoverOrphanedTransactionCommand(recoverOrphanedTransactionCommand) + .build()); + break; + } + } + } catch (Exception e) { + + } + } if (msg instanceof PollCommandResponse) { PollCommandResponse response = (PollCommandResponse) msg; future.complete(response); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 8ffffcc597..ed103d1bd4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -25,6 +25,7 @@ import apache.rocketmq.v1.ConsumerData; import apache.rocketmq.v1.Digest; import apache.rocketmq.v1.DigestType; import apache.rocketmq.v1.Encoding; +import apache.rocketmq.v1.EndTransactionRequest; import apache.rocketmq.v1.FilterExpression; import apache.rocketmq.v1.FilterType; import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; @@ -46,6 +47,7 @@ import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; import java.net.SocketAddress; +import java.net.UnknownHostException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -67,6 +69,7 @@ import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -75,6 +78,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -198,6 +202,33 @@ public class Converter { return consumerSendMsgBackRequestHeader; } + public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String messageId = request.getMessageId(); + String transactionId = request.getTransactionId(); + TransactionId handle; + try { + handle = TransactionId.decode(transactionId); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Parse transaction id failed", e); + } + long transactionStateTableOffset = handle.getTranStateTableOffset(); + long commitLogOffset = handle.getCommitLogOffset(); + boolean fromTransactionCheck = request.getSource() == EndTransactionRequest.Source.SERVER_CHECK; + int commitOrRollback = Converter.buildTransactionCommitOrRollback(request.getResolution()); + + EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); + endTransactionRequestHeader.setProducerGroup(groupName); + endTransactionRequestHeader.setMsgId(messageId); + endTransactionRequestHeader.setTransactionId(transactionId); + endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); + endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); + endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); + endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); + + return endTransactionRequestHeader; + } + public static Map buildMessageProperty(Message message) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties @@ -546,4 +577,15 @@ public class Converter { return systemAttributeBuilder.build(); } + public static int buildTransactionCommitOrRollback(EndTransactionRequest.TransactionResolution type) { + switch (type) { + case COMMIT: + return MessageSysFlag.TRANSACTION_COMMIT_TYPE; + case ROLLBACK: + return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; + default: + return MessageSysFlag.TRANSACTION_NOT_TYPE; + } + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index c5bd4658d6..74b1349acc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -32,6 +32,7 @@ import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NoopCommand; import apache.rocketmq.v1.NotifyClientTerminationRequest; import apache.rocketmq.v1.NotifyClientTerminationResponse; import apache.rocketmq.v1.PollCommandRequest; @@ -68,6 +69,7 @@ import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; @@ -304,7 +306,30 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - return null; + Channel channel = channelManager.createChannel(); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + + EndTransactionRequestHeader requestHeader = Converter.buildEndTransactionRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); + command.makeCustomHeaderToNet(); + + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand responseCommand = brokerController.getEndTransactionProcessor() + .processRequest(channelHandlerContext, command); + EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); + if (null != responseCommand) { + builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + } else { + builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); + } + EndTransactionResponse response = builder.build(); + future.complete(response); + } catch (Exception e) { + LOGGER.error("Exception raised while endTransaction", e); + future.completeExceptionally(e); + } + return future; } @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { @@ -323,12 +348,24 @@ public class LocalGrpcService implements GrpcForwardService { Resource producerGroup = request.getProducerGroup(); String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); + if (producerChannel == null) { + future.complete(PollCommandResponse.newBuilder() + .setNoopCommand(NoopCommand.newBuilder().build()) + .build()); + break; + } producerChannel.addClientObserver(future); break; case CONSUMER_GROUP: Resource consumerGroup = request.getConsumerGroup(); String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); + if (consumerChannel == null) { + future.complete(PollCommandResponse.newBuilder() + .setNoopCommand(NoopCommand.newBuilder().build()) + .build()); + break; + } consumerChannel.addClientObserver(future); break; default: From 10a7b3c9a28349d163046638e0c5aacd6475e537 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 16 Mar 2022 19:49:56 +0800 Subject: [PATCH 041/338] [ISSUE #3949] ack, nack for cluster mode --- .../connector/route/TopicRouteCache.java | 12 +- .../grpc/service/ClusterGrpcService.java | 7 +- .../DefaultAckMessageResponseConverter.java | 40 +++++ .../cluster/DefaultBrokerAddrConverter.java | 35 ++++ .../DefaultNackMessageResponseConverter.java | 40 +++++ .../cluster/ReceiveMessageService.java | 162 ++++++++++++++++-- 6 files changed, 281 insertions(+), 15 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index 752bb96b60..33507cdd87 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -23,14 +23,16 @@ import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.common.AbstractCacheLoader; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +67,14 @@ public class TopicRouteCache { return getCacheMessageQueueWrapper(this.topicCache, topicName); } + public String getBrokerAddr(String brokerName) throws Exception { + List brokerDataList = getMessageQueue(brokerName).getTopicRouteData().getBrokerDatas(); + if (brokerDataList.isEmpty()) { + return null; + } + return brokerDataList.get(0).getBrokerAddrs().get(MixAll.MASTER_ID); + } + public SelectableMessageQueue selectOneWriteQueue(String topic, SelectableMessageQueue last) throws Exception { if (last == null) { return getMessageQueue(topic).getWriteSelector().selectOne(false); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 0769c6be09..c06ae3acbd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -139,11 +139,12 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return null; + return this.receiveMessageService.ackMessage(ctx, request); } - @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - return null; + @Override + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { + return this.receiveMessageService.nackMessage(ctx, request); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java new file mode 100644 index 0000000000..1b3ac5578e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.AckMessageResponse; +import com.google.rpc.Code; +import io.grpc.Context; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; + +public class DefaultAckMessageResponseConverter implements ParameterConverter { + + @Override + public AckMessageResponse convert(Context ctx, AckResult ackResult) throws Throwable { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return AckMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + } + return AckMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "ack failed: status is abnormal")) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java new file mode 100644 index 0000000000..5314d2b06c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import io.grpc.Context; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; + +public class DefaultBrokerAddrConverter implements ParameterConverter { + + private final TopicRouteCache topicRouteCache; + + public DefaultBrokerAddrConverter(TopicRouteCache topicRouteCache) { + this.topicRouteCache = topicRouteCache; + } + + @Override + public String convert(Context ctx, String parameter) throws Throwable { + return this.topicRouteCache.getBrokerAddr(parameter); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java new file mode 100644 index 0000000000..513ee1a8fd --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.NackMessageResponse; +import com.google.rpc.Code; +import io.grpc.Context; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; + +public class DefaultNackMessageResponseConverter implements ParameterConverter { + + @Override + public NackMessageResponse convert(Context ctx, AckResult ackResult) throws Throwable { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + } + return NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java index 85c0418cf8..08c4b4fd3b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java @@ -18,13 +18,21 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; +import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; @@ -33,6 +41,7 @@ import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; public class ReceiveMessageService extends BaseService { @@ -41,33 +50,38 @@ public class ReceiveMessageService extends BaseService { private final ForwardWriteConsumer writeConsumer; private final TopicRouteCache topicRouteCache; + private ParameterConverter brokerAddrConverter; + private ParameterConverter receiptHandleConverter; + private ParameterConverter popResultResponseParameterConverter; private ReceiveMessageQueueSelector receiveMessageQueueSelector; private ResponseHook receiveMessageHook = null; + private ParameterConverter ackMessageRequestConverter; + private ParameterConverter ackMessageResponseConverter; private ResponseHook ackMessageHook = null; + private ParameterConverter nackMessageRequestConverter; + private ParameterConverter nackMessageResponseConverter; + private ResponseHook nackMessageHook = null; + public ReceiveMessageService(ConnectorManager connectorManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); this.topicRouteCache = connectorManager.getTopicRouteCache(); + this.brokerAddrConverter = (ctx, brokerName) -> this.topicRouteCache.getBrokerAddr(brokerName); + this.receiptHandleConverter = (ctx, handleStr) -> ReceiptHandle.decode(handleStr); + this.popResultResponseParameterConverter = new DefaultPopResultResponseParameterConverter(); this.receiveMessageQueueSelector = new DefaultReceiveMessageQueueSelector(connectorManager.getTopicRouteCache()); - } - public void setPopResultResponseParameterConverter( - ParameterConverter popResultResponseParameterConverter) { - this.popResultResponseParameterConverter = popResultResponseParameterConverter; - } + this.ackMessageRequestConverter = (ctx, request) -> Converter.buildAckMessageRequestHeader(request); + this.ackMessageResponseConverter = new DefaultAckMessageResponseConverter(); - public void setReceiveMessageQueueSelector(ReceiveMessageQueueSelector receiveMessageQueueSelector) { - this.receiveMessageQueueSelector = receiveMessageQueueSelector; - } - - public void setReceiveMessageHook(ResponseHook receiveMessageHook) { - this.receiveMessageHook = receiveMessageHook; + this.nackMessageRequestConverter = (ctx, request) -> Converter.buildChangeInvisibleTimeRequestHeader(request); + this.nackMessageResponseConverter = new DefaultNackMessageResponseConverter(); } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { @@ -106,4 +120,130 @@ public class ReceiveMessageService extends BaseService { } return future; } + + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (ackMessageHook != null) { + ackMessageHook.beforeResponse(request, response, throwable); + } + }); + try { + ReceiptHandle receiptHandle = receiptHandleConverter.convert(ctx, request.getReceiptHandle()); + if (receiptHandle.isExpired()) { + future.complete(AckMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "handle has expired")) + .build()); + return future; + } + + String brokerAddr = brokerAddrConverter.convert(ctx, receiptHandle.getBrokerName()); + AckMessageRequestHeader requestHeader = this.ackMessageRequestConverter.convert(ctx, request); + CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + ackResultFuture.thenAccept(result -> { + try { + future.complete(ackMessageResponseConverter.convert(ctx, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (nackMessageHook != null) { + nackMessageHook.beforeResponse(request, response, throwable); + } + }); + try { + ReceiptHandle receiptHandle = this.receiptHandleConverter.convert(ctx, request.getReceiptHandle()); + if (receiptHandle.isExpired()) { + future.complete(NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "handle has expired")) + .build()); + return future; + } + + String brokerAddr = brokerAddrConverter.convert(ctx, receiptHandle.getBrokerName()); + ChangeInvisibleTimeRequestHeader requestHeader = this.nackMessageRequestConverter.convert(ctx, request); + CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, + ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + resultFuture.thenAccept(result -> { + try { + future.complete(nackMessageResponseConverter.convert(ctx, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public void setBrokerAddrConverter( + ParameterConverter brokerAddrConverter) { + this.brokerAddrConverter = brokerAddrConverter; + } + + public void setReceiptHandleConverter( + ParameterConverter receiptHandleConverter) { + this.receiptHandleConverter = receiptHandleConverter; + } + + public void setPopResultResponseParameterConverter( + ParameterConverter popResultResponseParameterConverter) { + this.popResultResponseParameterConverter = popResultResponseParameterConverter; + } + + public void setReceiveMessageQueueSelector( + ReceiveMessageQueueSelector receiveMessageQueueSelector) { + this.receiveMessageQueueSelector = receiveMessageQueueSelector; + } + + public void setReceiveMessageHook( + ResponseHook receiveMessageHook) { + this.receiveMessageHook = receiveMessageHook; + } + + public void setAckMessageRequestConverter( + ParameterConverter ackMessageRequestConverter) { + this.ackMessageRequestConverter = ackMessageRequestConverter; + } + + public void setAckMessageResponseConverter( + ParameterConverter ackMessageResponseConverter) { + this.ackMessageResponseConverter = ackMessageResponseConverter; + } + + public void setAckMessageHook( + ResponseHook ackMessageHook) { + this.ackMessageHook = ackMessageHook; + } + + public void setNackMessageRequestConverter( + ParameterConverter nackMessageRequestConverter) { + this.nackMessageRequestConverter = nackMessageRequestConverter; + } + + public void setNackMessageResponseConverter( + ParameterConverter nackMessageResponseConverter) { + this.nackMessageResponseConverter = nackMessageResponseConverter; + } + + public void setNackMessageHook( + ResponseHook nackMessageHook) { + this.nackMessageHook = nackMessageHook; + } } From 1150aa99451d729d9f367abae4d311914c27f2e1 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 17 Mar 2022 11:31:47 +0800 Subject: [PATCH 042/338] [ISSUE #3949] pull message for cluster mode and code refactor --- .../client/impl/MQClientAPIExtImpl.java | 66 +++++++ .../utils/FilterUtil.java} | 21 ++- .../proxy/connector/DefaultForwardClient.java | 9 + .../connector/route/TopicRouteCache.java | 4 - .../rocketmq/proxy/grpc/common/Converter.java | 33 +++- .../proxy/grpc/common/ProxyException.java | 14 +- .../proxy/grpc/common/ResponseBuilder.java | 7 - .../grpc/service/ClusterGrpcService.java | 13 +- .../grpc/service/cluster/BaseService.java | 24 +++ .../DefaultAckMessageResponseConverter.java | 40 ---- .../cluster/DefaultBrokerAddrConverter.java | 35 ---- .../DefaultNackMessageResponseConverter.java | 40 ---- ...ltPopResultResponseParameterConverter.java | 62 ------ .../DefaultProducerRequestConverter.java | 31 --- .../DefaultProducerResponseConverter.java | 43 ----- .../grpc/service/cluster/ProducerService.java | 62 +++--- .../service/cluster/PullMessageService.java | 172 +++++++++++++++++ .../cluster/ReceiveMessageService.java | 176 +++++++++--------- .../DefaultProducerQueueSelectorTest.java | 20 +- .../service/cluster/ProducerServiceTest.java | 3 +- 20 files changed, 455 insertions(+), 420 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/service/cluster/DefaultProducerMessageConverter.java => common/utils/FilterUtil.java} (60%) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java index ce3c548424..a515ea138f 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -37,8 +37,12 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHead import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SearchOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; @@ -293,4 +297,66 @@ public class MQClientAPIExtImpl { public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { return this.mqClientAPI.getTopicRouteInfoFromNameServer(topic, timeoutMillis); } + + public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); + this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { + RemotingCommand response = responseFuture.getResponseCommand(); + if (response != null) { + if (ResponseCode.SUCCESS == response.getCode()) { + try { + GetMaxOffsetResponseHeader responseHeader = + (GetMaxOffsetResponseHeader) response.decodeCommandCustomHeader(GetMaxOffsetResponseHeader.class); + future.complete(responseHeader.getOffset()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark())); + } else { + future.completeExceptionally(processNullResponseErr(responseFuture)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture searchOffset(String brokerAddr, String topic, int queueId , long timestamp, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + requestHeader.setTimestamp(timestamp); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); + 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)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java similarity index 60% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java index 841aea9330..d5db649da0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerMessageConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java @@ -14,17 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.common.utils; -import apache.rocketmq.v1.Message; -import io.grpc.Context; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import java.util.Set; -public class DefaultProducerMessageConverter implements ParameterConverter { - - @Override - public org.apache.rocketmq.common.message.Message convert(Context ctx, Message parameter) { - return Converter.buildMessage(parameter); +public class FilterUtil { + public static boolean isTagNotMatched(Set tagsSet, String tags) { + if (tagsSet.isEmpty()) { + return false; + } + if (tags == null) { + return true; + } + return !tagsSet.contains(tags); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 1c298311f7..88b9b4a9cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -63,4 +63,13 @@ public class DefaultForwardClient extends AbstractForwardClient { throws RemotingException, InterruptedException, MQClientException { return getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } + + public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId, long timeoutMillis) { + return getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); + } + + public CompletableFuture searchOffset(String brokerAddr, String topic, int queueId, long timestamp, + long timeoutMillis) { + return getClient().searchOffset(brokerAddr, topic, queueId, timestamp, timeoutMillis); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index 33507cdd87..746f4ad430 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -127,10 +127,6 @@ public class TopicRouteCache { protected abstract TopicRouteData loadTopicRouteData(String topic) throws Exception; - protected boolean refreshBrokerAddrTable() { - return false; - } - @Override public MessageQueueWrapper getDirectly(String topic) throws Exception { try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index ed103d1bd4..e6b84a9ac3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -35,6 +35,7 @@ import apache.rocketmq.v1.MessageType; import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.ProducerData; +import apache.rocketmq.v1.PullMessageRequest; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; @@ -46,6 +47,7 @@ import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import com.google.rpc.Code; import java.net.SocketAddress; import java.net.UnknownHostException; import java.util.Arrays; @@ -71,12 +73,14 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHead import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.slf4j.Logger; @@ -229,6 +233,33 @@ public class Converter { return endTransactionRequestHeader; } + public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTime) { + Partition partition = request.getPartition(); + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); + + int queueId = partition.getId(); + int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); + String expression = request.getFilterExpression() + .getExpression(); + String expressionType = Converter.buildExpressionType(request.getFilterExpression() + .getType()); + + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup(groupName); + requestHeader.setTopic(topicName); + requestHeader.setQueueId(queueId); + requestHeader.setQueueOffset(request.getOffset()); + requestHeader.setMaxMsgNums(request.getBatchSize()); + requestHeader.setSysFlag(sysFlag); + requestHeader.setCommitOffset(0L); + requestHeader.setSuspendTimeoutMillis(pollTime); + requestHeader.setSubscription(expression); + requestHeader.setSubVersion(0L); + requestHeader.setExpressionType(expressionType); + return requestHeader; + } + public static Map buildMessageProperty(Message message) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties @@ -405,7 +436,7 @@ public class Converter { try { return FilterAPI.build(topicName, expression, expressionType); } catch (Exception e) { - throw new IllegalArgumentException("Build subscription failed when apply heartbeat", e); + throw new ProxyException(Code.INVALID_ARGUMENT, "expression format is not correct", e); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java index 093b9424f4..f476044383 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java @@ -16,21 +16,23 @@ */ package org.apache.rocketmq.proxy.grpc.common; +import com.google.rpc.Code; + public class ProxyException extends RuntimeException { - private final ProxyResponseCode code; + private final Code code; - public ProxyException(ProxyResponseCode proxyResponseCode, String errorMessage) { + public ProxyException(Code code, String errorMessage) { super(errorMessage); - this.code = proxyResponseCode; + this.code = code; } - public ProxyException(ProxyResponseCode proxyResponseCode, String message, Throwable cause) { + public ProxyException(Code code, String message, Throwable cause) { super(message, cause); - this.code = proxyResponseCode; + this.code = code; } - public ProxyResponseCode getCode() { + public Code getCode() { return code; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index ad519f4faa..25eddefd7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -18,18 +18,11 @@ package org.apache.rocketmq.proxy.grpc.common; import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.ResponseCommon; import apache.rocketmq.v1.SendMessageResponse; -import apache.rocketmq.v1.SystemAttribute; -import com.google.protobuf.ByteString; import com.google.rpc.Code; import com.google.rpc.Status; -import java.util.Map; import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.remoting.protocol.RemotingCommand; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index c06ae3acbd..830fed4281 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -68,6 +68,7 @@ import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; +import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; @@ -87,6 +88,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ReceiveMessageService receiveMessageService; private final RouteService routeService; private final ClientService clientService; + private final PullMessageService pullMessageService; public ClusterGrpcService() { this.channelManager = new ChannelManager(); @@ -96,6 +98,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(connectorManager); this.clientService = new ClientService(scheduledExecutorService); + this.pullMessageService = new PullMessageService(connectorManager); this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); this.appendStartAndShutdown(this.connectorManager); @@ -158,12 +161,14 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return null; } - @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return null; + @Override + public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { + return this.pullMessageService.queryOffset(ctx, request); } - @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return null; + @Override + public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { + return this.pullMessageService.pullMessage(ctx, request); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index 87b42ce706..fd2854da15 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -16,7 +16,12 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import com.google.rpc.Code; +import io.grpc.Context; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.grpc.common.ProxyException; public class BaseService { @@ -25,4 +30,23 @@ public class BaseService { public BaseService(ConnectorManager connectorManager) { this.connectorManager = connectorManager; } + + protected ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { + ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); + if (receiptHandle.isExpired()) { + throw new ProxyException(Code.INVALID_ARGUMENT, "handle has expired"); + } + return receiptHandle; + } + + protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { + if (StringUtils.isBlank(brokerName)) { + throw new ProxyException(Code.INVALID_ARGUMENT, "broker name is empty"); + } + String addr = this.connectorManager.getTopicRouteCache().getBrokerAddr(brokerName); + if (StringUtils.isBlank(addr)) { + throw new ProxyException(Code.NOT_FOUND, brokerName + " not exist"); + } + return addr; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java deleted file mode 100644 index 1b3ac5578e..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAckMessageResponseConverter.java +++ /dev/null @@ -1,40 +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.proxy.grpc.service.cluster; - -import apache.rocketmq.v1.AckMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; - -public class DefaultAckMessageResponseConverter implements ParameterConverter { - - @Override - public AckMessageResponse convert(Context ctx, AckResult ackResult) throws Throwable { - if (AckStatus.OK.equals(ackResult.getStatus())) { - return AckMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build(); - } - return AckMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "ack failed: status is abnormal")) - .build(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java deleted file mode 100644 index 5314d2b06c..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultBrokerAddrConverter.java +++ /dev/null @@ -1,35 +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.proxy.grpc.service.cluster; - -import io.grpc.Context; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; - -public class DefaultBrokerAddrConverter implements ParameterConverter { - - private final TopicRouteCache topicRouteCache; - - public DefaultBrokerAddrConverter(TopicRouteCache topicRouteCache) { - this.topicRouteCache = topicRouteCache; - } - - @Override - public String convert(Context ctx, String parameter) throws Throwable { - return this.topicRouteCache.getBrokerAddr(parameter); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java deleted file mode 100644 index 513ee1a8fd..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultNackMessageResponseConverter.java +++ /dev/null @@ -1,40 +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.proxy.grpc.service.cluster; - -import apache.rocketmq.v1.NackMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; - -public class DefaultNackMessageResponseConverter implements ParameterConverter { - - @Override - public NackMessageResponse convert(Context ctx, AckResult ackResult) throws Throwable { - if (AckStatus.OK.equals(ackResult.getStatus())) { - return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build(); - } - return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) - .build(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java deleted file mode 100644 index 7d960f85fa..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultPopResultResponseParameterConverter.java +++ /dev/null @@ -1,62 +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.proxy.grpc.service.cluster; - -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.ReceiveMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.List; -import org.apache.rocketmq.client.consumer.PopResult; -import org.apache.rocketmq.client.consumer.PopStatus; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; - -public class DefaultPopResultResponseParameterConverter implements ParameterConverter { - - @Override - public ReceiveMessageResponse convert(Context ctx, PopResult result) throws Throwable { - PopStatus status = result.getPopStatus(); - switch (status) { - case FOUND: - break; - case POLLING_FULL: - return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.RESOURCE_EXHAUSTED, "polling full")) - .build(); - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, "no new message")) - .build(); - } - - List messages = new ArrayList<>(); - for (MessageExt messageExt : result.getMsgFoundList()) { - messages.add(Converter.buildMessage(messageExt)); - } - - return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .addAllMessages(messages) - .build(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java deleted file mode 100644 index cfe62ce7a2..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerRequestConverter.java +++ /dev/null @@ -1,31 +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.proxy.grpc.service.cluster; - -import apache.rocketmq.v1.SendMessageRequest; -import io.grpc.Context; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; - -public class DefaultProducerRequestConverter implements ParameterConverter { - - @Override - public SendMessageRequestHeader convert(Context ctx, SendMessageRequest parameter) { - return Converter.buildSendMessageRequestHeader(parameter); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java deleted file mode 100644 index db5095128f..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerResponseConverter.java +++ /dev/null @@ -1,43 +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.proxy.grpc.service.cluster; - -import apache.rocketmq.v1.SendMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; - -public class DefaultProducerResponseConverter implements ParameterConverter { - - @Override - public SendMessageResponse convert(Context ctx, SendResult sendResult) { - if (sendResult.getSendStatus() != SendStatus.SEND_OK) { - return SendMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) - .build(); - } - return SendMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) - .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) - .build(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 7478e2f3ed..cc00a0968d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -16,56 +16,33 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Message; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; +import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; -import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class ProducerService extends BaseService { - private static final Logger log = LoggerFactory.getLogger(ProducerService.class); - - private volatile ParameterConverter parameterConverter; - private volatile ParameterConverter messageConverter; - private volatile ParameterConverter responseConverter; private volatile ProducerQueueSelector messageQueueSelector; private volatile ResponseHook producerServiceHook = null; public ProducerService(ConnectorManager connectorManager) { super(connectorManager); - - parameterConverter = new DefaultProducerRequestConverter(); - messageConverter = new DefaultProducerMessageConverter(); - responseConverter = new DefaultProducerResponseConverter(); messageQueueSelector = new DefaultProducerQueueSelector(this.connectorManager.getTopicRouteCache()); } - public void setParameterConverter( - ParameterConverter parameterConverter) { - this.parameterConverter = parameterConverter; - } - - public void setMessageConverter( - ParameterConverter messageConverter) { - this.messageConverter = messageConverter; - } - - public void setResponseConverter(ParameterConverter responseConverter) { - this.responseConverter = responseConverter; - } - public void setProducerServiceHook(ResponseHook producerServiceHook) { this.producerServiceHook = producerServiceHook; } @@ -83,14 +60,14 @@ public class ProducerService extends BaseService { }); try { - org.apache.rocketmq.common.message.Message message = messageConverter.convert(ctx, request.getMessage()); - SendMessageRequestHeader requestHeader = this.parameterConverter.convert(ctx, request); + Pair requestPair = this.convert(ctx, request); + SendMessageRequestHeader requestHeader = requestPair.getLeft(); + org.apache.rocketmq.common.message.Message message = requestPair.getRight(); SelectableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); if (addressableMessageQueue == null) { - throw new ProxyException(ProxyResponseCode.NO_TOPIC_ROUTE, - "no writeable topic route for topic " + topic); + throw new ProxyException(Code.NOT_FOUND, "no writeable topic route for topic " + topic); } CompletableFuture sendResultCompletableFuture = this.connectorManager.getForwardProducer().sendMessage( @@ -103,7 +80,7 @@ public class ProducerService extends BaseService { sendResultCompletableFuture .thenAccept(result -> { try { - future.complete(this.responseConverter.convert(ctx, result)); + future.complete(convertToSendMessageResponse(ctx, request, result)); } catch (Throwable throwable) { future.completeExceptionally(throwable); } @@ -117,4 +94,21 @@ public class ProducerService extends BaseService { } return future; } + + protected Pair convert(Context ctx, SendMessageRequest request) { + return Pair.of(Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); + } + + protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult sendResult) { + if (sendResult.getSendStatus() != SendStatus.SEND_OK) { + return SendMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) + .build(); + } + return SendMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) + .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) + .build(); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java new file mode 100644 index 0000000000..e406410ffa --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -0,0 +1,172 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryOffsetPolicy; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import com.google.protobuf.util.Timestamps; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.consumer.PullStatus; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.utils.FilterUtil; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.DefaultForwardClient; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.common.ResponseHook; + +public class PullMessageService extends BaseService { + + private final DefaultForwardClient defaultForwardClient; + + private volatile ResponseHook queryOffsetHook = null; + + private volatile ResponseHook pullMessageHook = null; + + public PullMessageService(ConnectorManager connectorManager) { + super(connectorManager); + this.defaultForwardClient = connectorManager.getDefaultForwardClient(); + } + + public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (queryOffsetHook != null) { + queryOffsetHook.beforeResponse(request, response, throwable); + } + }); + try { + Partition partition = request.getPartition(); + String topic = Converter.getResourceNameWithNamespace(partition.getTopic()); + + String brokerName = partition.getBroker().getName(); + int queueId = partition.getId(); + CompletableFuture offsetFuture; + if (request.getPolicy() == QueryOffsetPolicy.BEGINNING) { + offsetFuture = CompletableFuture.completedFuture(0L); + } else if (request.getPolicy() == QueryOffsetPolicy.END) { + String brokerAddr = this.getBrokerAddr(ctx, brokerName); + offsetFuture = this.defaultForwardClient.getMaxOffset(brokerAddr, topic, queueId, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } else { + long timestamp = Timestamps.toMillis(request.getTimePoint()); + String brokerAddr = this.getBrokerAddr(ctx, brokerName); + offsetFuture = this.defaultForwardClient.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + offsetFuture.thenAccept(result -> { + future.complete(QueryOffsetResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setOffset(result) + .build()); + }).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (pullMessageHook != null) { + pullMessageHook.beforeResponse(request, response, throwable); + } + }); + try { + PullMessageRequestHeader requestHeader = this.convertToPullMessageRequestHeader(ctx, request); + + String brokerName = request.getPartition().getBroker().getName(); + String brokerAddr = this.getBrokerAddr(ctx, brokerName); + + CompletableFuture pullResultFuture = this.connectorManager.getForwardReadConsumer() + .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + pullResultFuture.thenAccept(pullResult -> { + try { + future.complete(convertToPullMessageResponse(ctx, request, pullResult)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected PullMessageRequestHeader convertToPullMessageRequestHeader(Context ctx, PullMessageRequest request) { + // check filterExpression is correct or not + Converter.buildSubscriptionData(Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + + long pollTime = ctx.getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS) - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + throw new ProxyException(Code.DEADLINE_EXCEEDED, "request has been canceled due to timeout"); + } + return Converter.buildPullMessageRequestHeader(request, pollTime); + } + + protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { + SubscriptionData subscriptionData = Converter.buildSubscriptionData( + Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + + PullStatus status = result.getPullStatus(); + if (status.equals(PullStatus.FOUND)) { + List messages = new ArrayList<>(); + for (MessageExt messageExt : result.getMsgFoundList()) { + if (FilterUtil.isTagNotMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + continue; + } + messages.add(Converter.buildMessage(messageExt)); + } + return PullMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setMinOffset(result.getMinOffset()) + .setMaxOffset(result.getMaxOffset()) + .setNextOffset(result.getNextBeginOffset()) + .addAllMessages(messages) + .build(); + } else { + return PullMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setMinOffset(result.getMinOffset()) + .setMaxOffset(result.getMaxOffset()) + .setNextOffset(result.getNextBeginOffset()) + .build(); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java index 08c4b4fd3b..0019656611 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java @@ -18,17 +18,23 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.Message; import apache.rocketmq.v1.NackMessageRequest; import apache.rocketmq.v1.NackMessageResponse; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import com.google.rpc.Code; import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; @@ -38,9 +44,7 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; @@ -48,40 +52,18 @@ public class ReceiveMessageService extends BaseService { private final ForwardReadConsumer readConsumer; private final ForwardWriteConsumer writeConsumer; - private final TopicRouteCache topicRouteCache; - private ParameterConverter brokerAddrConverter; - private ParameterConverter receiptHandleConverter; - - private ParameterConverter popResultResponseParameterConverter; - private ReceiveMessageQueueSelector receiveMessageQueueSelector; - private ResponseHook receiveMessageHook = null; - - private ParameterConverter ackMessageRequestConverter; - private ParameterConverter ackMessageResponseConverter; - private ResponseHook ackMessageHook = null; - - private ParameterConverter nackMessageRequestConverter; - private ParameterConverter nackMessageResponseConverter; - private ResponseHook nackMessageHook = null; + private volatile ReceiveMessageQueueSelector receiveMessageQueueSelector; + private volatile ResponseHook receiveMessageHook = null; + private volatile ResponseHook ackMessageHook = null; + private volatile ResponseHook nackMessageHook = null; public ReceiveMessageService(ConnectorManager connectorManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); - this.topicRouteCache = connectorManager.getTopicRouteCache(); - this.brokerAddrConverter = (ctx, brokerName) -> this.topicRouteCache.getBrokerAddr(brokerName); - this.receiptHandleConverter = (ctx, handleStr) -> ReceiptHandle.decode(handleStr); - - this.popResultResponseParameterConverter = new DefaultPopResultResponseParameterConverter(); this.receiveMessageQueueSelector = new DefaultReceiveMessageQueueSelector(connectorManager.getTopicRouteCache()); - - this.ackMessageRequestConverter = (ctx, request) -> Converter.buildAckMessageRequestHeader(request); - this.ackMessageResponseConverter = new DefaultAckMessageResponseConverter(); - - this.nackMessageRequestConverter = (ctx, request) -> Converter.buildChangeInvisibleTimeRequestHeader(request); - this.nackMessageResponseConverter = new DefaultNackMessageResponseConverter(); } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { @@ -92,25 +74,17 @@ public class ReceiveMessageService extends BaseService { } }); try { - long timeRemaining = Context.current() - .getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - - PopMessageRequestHeader requestHeader = Converter.buildPopMessageRequestHeader(request, pollTime); + PopMessageRequestHeader requestHeader = this.convertToPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.receiveMessageQueueSelector.select(ctx, request, requestHeader); CompletableFuture popResultFuture = this.readConsumer.popMessage( messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), requestHeader, - pollTime); + requestHeader.getPollTime()); popResultFuture.thenAccept(result -> { try { - future.complete(popResultResponseParameterConverter.convert(ctx, result)); + future.complete(convertToReceiveMessageResponse(ctx, request, result)); } catch (Throwable throwable) { future.completeExceptionally(throwable); } @@ -121,6 +95,45 @@ public class ReceiveMessageService extends BaseService { return future; } + protected PopMessageRequestHeader convertToPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { + long timeRemaining = ctx.getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + + return Converter.buildPopMessageRequestHeader(request, pollTime); + } + + protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { + PopStatus status = result.getPopStatus(); + switch (status) { + case FOUND: + break; + case POLLING_FULL: + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.RESOURCE_EXHAUSTED, "polling full")) + .build(); + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, "no new message")) + .build(); + } + + List messages = new ArrayList<>(); + for (MessageExt messageExt : result.getMsgFoundList()) { + messages.add(Converter.buildMessage(messageExt)); + } + + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .addAllMessages(messages) + .build(); + } + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -129,20 +142,14 @@ public class ReceiveMessageService extends BaseService { } }); try { - ReceiptHandle receiptHandle = receiptHandleConverter.convert(ctx, request.getReceiptHandle()); - if (receiptHandle.isExpired()) { - future.complete(AckMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "handle has expired")) - .build()); - return future; - } + ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - String brokerAddr = brokerAddrConverter.convert(ctx, receiptHandle.getBrokerName()); - AckMessageRequestHeader requestHeader = this.ackMessageRequestConverter.convert(ctx, request); + AckMessageRequestHeader requestHeader = this.convertToAckMessageRequestHeader(ctx, request); CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); ackResultFuture.thenAccept(result -> { try { - future.complete(ackMessageResponseConverter.convert(ctx, result)); + future.complete(convertToAckMessageResponse(ctx, request, result)); } catch (Throwable throwable) { future.completeExceptionally(throwable); } @@ -156,6 +163,21 @@ public class ReceiveMessageService extends BaseService { return future; } + protected AckMessageRequestHeader convertToAckMessageRequestHeader(Context ctx, AckMessageRequest request) { + return Converter.buildAckMessageRequestHeader(request); + } + + protected AckMessageResponse convertToAckMessageResponse(Context ctx, AckMessageRequest request, AckResult ackResult) { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return AckMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + } + return AckMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "ack failed: status is abnormal")) + .build(); + } + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -164,21 +186,15 @@ public class ReceiveMessageService extends BaseService { } }); try { - ReceiptHandle receiptHandle = this.receiptHandleConverter.convert(ctx, request.getReceiptHandle()); - if (receiptHandle.isExpired()) { - future.complete(NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "handle has expired")) - .build()); - return future; - } + ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - String brokerAddr = brokerAddrConverter.convert(ctx, receiptHandle.getBrokerName()); - ChangeInvisibleTimeRequestHeader requestHeader = this.nackMessageRequestConverter.convert(ctx, request); + ChangeInvisibleTimeRequestHeader requestHeader = this.convertToChangeInvisibleTimeRequestHeader(ctx, request); CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); resultFuture.thenAccept(result -> { try { - future.complete(nackMessageResponseConverter.convert(ctx, result)); + future.complete(convertToNackMessageResponse(ctx, request, result)); } catch (Throwable throwable) { future.completeExceptionally(throwable); } @@ -192,19 +208,19 @@ public class ReceiveMessageService extends BaseService { return future; } - public void setBrokerAddrConverter( - ParameterConverter brokerAddrConverter) { - this.brokerAddrConverter = brokerAddrConverter; + protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { + return Converter.buildChangeInvisibleTimeRequestHeader(request); } - public void setReceiptHandleConverter( - ParameterConverter receiptHandleConverter) { - this.receiptHandleConverter = receiptHandleConverter; - } - - public void setPopResultResponseParameterConverter( - ParameterConverter popResultResponseParameterConverter) { - this.popResultResponseParameterConverter = popResultResponseParameterConverter; + protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build(); + } + return NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) + .build(); } public void setReceiveMessageQueueSelector( @@ -217,31 +233,11 @@ public class ReceiveMessageService extends BaseService { this.receiveMessageHook = receiveMessageHook; } - public void setAckMessageRequestConverter( - ParameterConverter ackMessageRequestConverter) { - this.ackMessageRequestConverter = ackMessageRequestConverter; - } - - public void setAckMessageResponseConverter( - ParameterConverter ackMessageResponseConverter) { - this.ackMessageResponseConverter = ackMessageResponseConverter; - } - public void setAckMessageHook( ResponseHook ackMessageHook) { this.ackMessageHook = ackMessageHook; } - public void setNackMessageRequestConverter( - ParameterConverter nackMessageRequestConverter) { - this.nackMessageRequestConverter = nackMessageRequestConverter; - } - - public void setNackMessageResponseConverter( - ParameterConverter nackMessageResponseConverter) { - this.nackMessageResponseConverter = nackMessageResponseConverter; - } - public void setNackMessageHook( ResponseHook nackMessageHook) { this.nackMessageHook = nackMessageHook; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java index 99f662d956..35495513fe 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java @@ -12,6 +12,7 @@ import java.nio.charset.StandardCharsets; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.grpc.common.Converter; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -22,9 +23,6 @@ import static org.mockito.Mockito.when; public class DefaultProducerQueueSelectorTest extends BaseServiceTest { - private final DefaultProducerRequestConverter requestConverter = new DefaultProducerRequestConverter(); - private final DefaultProducerMessageConverter messageConverter = new DefaultProducerMessageConverter(); - @Override public void beforeEach() throws Throwable { SelectableMessageQueue queue = new SelectableMessageQueue( @@ -63,8 +61,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - requestConverter.convert(Context.current(), request), - messageConverter.convert(Context.current(), request.getMessage())); + Converter.buildSendMessageRequestHeader(request), + Converter.buildMessage(request.getMessage())); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -87,8 +85,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - requestConverter.convert(Context.current(), request), - messageConverter.convert(Context.current(), request.getMessage())); + Converter.buildSendMessageRequestHeader(request), + Converter.buildMessage(request.getMessage())); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -110,8 +108,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - requestConverter.convert(Context.current(), request), - messageConverter.convert(Context.current(), request.getMessage())); + Converter.buildSendMessageRequestHeader(request), + Converter.buildMessage(request.getMessage())); assertEquals("selectNormalQueue", queue.getBrokerName()); assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); @@ -138,8 +136,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - requestConverter.convert(Context.current(), request), - messageConverter.convert(Context.current(), request.getMessage())); + Converter.buildSendMessageRequestHeader(request), + Converter.buildMessage(request.getMessage())); assertEquals("selectTargetQueue", queue.getBrokerName()); assertEquals("selectTargetQueueAddr", queue.getBrokerAddr()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 4f3d17ff1b..2653ed31d2 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -32,7 +32,6 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.common.ProxyException; -import org.apache.rocketmq.proxy.grpc.common.ProxyResponseCode; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -113,7 +112,7 @@ public class ProducerServiceTest extends BaseServiceTest { assertNotNull(e); assertTrue(e instanceof ExecutionException); assertTrue(e.getCause() instanceof ProxyException); - assertEquals(ProxyResponseCode.NO_TOPIC_ROUTE, ((ProxyException) e.getCause()).getCode()); + assertEquals(Code.NOT_FOUND, ((ProxyException) e.getCause()).getCode()); } } From fe96159a4675e1c929959b2c96681c816b6c7743 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 17 Mar 2022 15:30:26 +0800 Subject: [PATCH 043/338] [ISSUE #3949] transaction support for cluster mode --- .../client/impl/MQClientAPIExtImpl.java | 6 + .../proxy/channel/ChannelManager.java | 23 +- .../rocketmq/proxy/config/ProxyConfig.java | 37 +++ .../proxy/connector/ConnectorManager.java | 8 + .../proxy/connector/ForwardProducer.java | 38 ++- .../TransactionHeartbeatRegisterService.java | 236 ++++++++++++++++++ .../connector/transaction/TransactionId.java | 34 +-- .../adapter/channel/GrpcClientChannel.java | 17 +- .../grpc/service/ClusterGrpcService.java | 18 +- .../grpc/service/cluster/ProducerService.java | 9 + .../service/cluster/TransactionService.java | 117 +++++++++ 11 files changed, 516 insertions(+), 27 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java index a515ea138f..d77159d87d 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -35,6 +35,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; @@ -117,6 +118,11 @@ public class MQClientAPIExtImpl { return future; } + public void endTransactionOneway(String brokerAddr, EndTransactionRequestHeader requestHeader, String remark, long timeoutMillis) + throws MQBrokerException, RemotingException, InterruptedException { + this.mqClientAPI.endTransactionOneway(brokerAddr, requestHeader, remark, timeoutMillis); + } + public CompletableFuture sendMessage(String brokerAddr, String brokerName, Message msg, SendMessageRequestHeader requestHeader, long timeoutMillis) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 54a54f32be..1d27b1633c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -19,16 +19,19 @@ package org.apache.rocketmq.proxy.channel; import com.google.common.base.Strings; import io.grpc.Context; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.common.Cleaner; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +39,7 @@ import org.slf4j.LoggerFactory; public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); - private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); + private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { return createChannel(anonymousChannelId()); @@ -102,10 +105,14 @@ public class ChannelManager { } public void addGroupClientId(String group, String clientId) { - groupClientIdMap.computeIfAbsent(group, k -> new CopyOnWriteArrayList<>()) + groupClientIdMap.computeIfAbsent(group, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())) .add(clientId); } + public List getClientIdList(String group) { + return new ArrayList<>(groupClientIdMap.get(group)); + } + /** * Scan and remove inactive mocking channels; Scan and clean expired requests; */ @@ -116,6 +123,16 @@ public class ChannelManager { Map.Entry entry = iterator.next(); if (!entry.getValue().isActive()) { iterator.remove(); + if (entry.getValue() instanceof GrpcClientChannel) { + GrpcClientChannel grpcClientChannel = (GrpcClientChannel) entry.getValue(); + groupClientIdMap.computeIfPresent(grpcClientChannel.getGroup(), (group, clientIds) -> { + clientIds.remove(grpcClientChannel.getClientId()); + if (clientIds.isEmpty()) { + return null; + } + return clientIds; + }); + } } else { if (entry.getValue() instanceof Cleaner) { Cleaner cleaner = (Cleaner) entry.getValue(); 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 15ee0f108e..9c40facf87 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 @@ -72,6 +72,11 @@ public class ProxyConfig { private int topicRouteThreadPoolNums = 36; private int topicRouteThreadPoolQueueCapacity = 50000; + private int transactionHeartbeatThreadPoolNums = 20; + private int transactionHeartbeatThreadPoolQueueCapacity = 200; + private int transactionHeartbeatPeriodSecond = 20; + private int transactionHeartbeatBatchNum = 100; + private int longPollingReserveTimeInMillis = 10000; public Integer getHealthCheckPort() { @@ -322,6 +327,38 @@ public class ProxyConfig { this.topicRouteThreadPoolQueueCapacity = topicRouteThreadPoolQueueCapacity; } + public int getTransactionHeartbeatThreadPoolNums() { + return transactionHeartbeatThreadPoolNums; + } + + public void setTransactionHeartbeatThreadPoolNums(int transactionHeartbeatThreadPoolNums) { + this.transactionHeartbeatThreadPoolNums = transactionHeartbeatThreadPoolNums; + } + + public int getTransactionHeartbeatThreadPoolQueueCapacity() { + return transactionHeartbeatThreadPoolQueueCapacity; + } + + public void setTransactionHeartbeatThreadPoolQueueCapacity(int transactionHeartbeatThreadPoolQueueCapacity) { + this.transactionHeartbeatThreadPoolQueueCapacity = transactionHeartbeatThreadPoolQueueCapacity; + } + + public int getTransactionHeartbeatPeriodSecond() { + return transactionHeartbeatPeriodSecond; + } + + public void setTransactionHeartbeatPeriodSecond(int transactionHeartbeatPeriodSecond) { + this.transactionHeartbeatPeriodSecond = transactionHeartbeatPeriodSecond; + } + + public int getTransactionHeartbeatBatchNum() { + return transactionHeartbeatBatchNum; + } + + public void setTransactionHeartbeatBatchNum(int transactionHeartbeatBatchNum) { + this.transactionHeartbeatBatchNum = transactionHeartbeatBatchNum; + } + public int getLongPollingReserveTimeInMillis() { return longPollingReserveTimeInMillis; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java index 01ec55fb62..8ae3c8d7aa 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.connector; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; @@ -29,6 +30,7 @@ public class ConnectorManager extends AbstractStartAndShutdown { private final ForwardWriteConsumer forwardWriteConsumer; private final TopicRouteCache topicRouteCache; + private final TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; public ConnectorManager(TransactionStateChecker transactionStateChecker) { this.forwardClientFactory = new ForwardClientFactory(transactionStateChecker); @@ -38,12 +40,14 @@ public class ConnectorManager extends AbstractStartAndShutdown { this.forwardWriteConsumer = new ForwardWriteConsumer(this.forwardClientFactory); this.topicRouteCache = new TopicRouteCache(this.defaultForwardClient); + this.transactionHeartbeatRegisterService = new TransactionHeartbeatRegisterService(this.forwardProducer, this.topicRouteCache); this.appendStartAndShutdown(this.forwardClientFactory); this.appendStartAndShutdown(this.defaultForwardClient); this.appendStartAndShutdown(this.forwardProducer); this.appendStartAndShutdown(this.forwardReadConsumer); this.appendStartAndShutdown(this.forwardWriteConsumer); + this.appendStartAndShutdown(this.transactionHeartbeatRegisterService); } public ForwardClientFactory getForwardClientFactory() { @@ -69,4 +73,8 @@ public class ConnectorManager extends AbstractStartAndShutdown { public TopicRouteCache getTopicRouteCache() { return topicRouteCache; } + + public TransactionHeartbeatRegisterService getTransactionHeartbeatRegisterService() { + return transactionHeartbeatRegisterService; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index cc0e5ba9ce..d35b65fd24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -17,14 +17,19 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ForwardProducer extends AbstractForwardClient { @@ -57,9 +62,38 @@ public class ForwardProducer extends AbstractForwardClient { return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); } + public void endTransaction(EndTransactionRequestHeader request, long timeoutMillis) throws Exception { + TransactionId transactionId = TransactionId.decode(request.getTransactionId()); + + EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); + requestHeader.setProducerGroup(request.getProducerGroup()); + requestHeader.setTranStateTableOffset(transactionId.getTranStateTableOffset()); + requestHeader.setCommitLogOffset(transactionId.getCommitLogOffset()); + requestHeader.setFromTransactionCheck(request.getFromTransactionCheck()); + requestHeader.setMsgId(request.getMsgId()); + requestHeader.setTransactionId(transactionId.getBrokerTransactionId()); + requestHeader.setCommitOrRollback(request.getCommitOrRollback()); + + String brokerAddr = RemotingHelper.parseSocketAddressAddr(transactionId.getBrokerAddr()); + this.getClient().endTransactionOneway( + brokerAddr, + requestHeader, + "end transaction from rmq proxy", + timeoutMillis + ); + } + public CompletableFuture sendMessage(String address, String brokerName, Message msg, SendMessageRequestHeader requestHeader, long timeoutMillis) { - return this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); + CompletableFuture future = this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); + future.thenApply(sendResult -> { + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && !StringUtils.isEmpty(sendResult.getTransactionId())) { + TransactionId transactionId = TransactionId.genFromBrokerTransactionId(address, sendResult); + sendResult.setTransactionId(transactionId.getProxyTransactionId()); + } + return sendResult; + }); + return future; } public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java new file mode 100644 index 0000000000..5ae71d5f9b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -0,0 +1,236 @@ +/* + * 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.connector.transaction; + +import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.connector.ForwardProducer; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransactionHeartbeatRegisterService implements StartAndShutdown { + + private static final Logger log = LoggerFactory.getLogger(TransactionHeartbeatRegisterService.class); + + private static final String TRANS_HEARTBEAT_CLIENT_ID = "rmq-proxy-producer-client"; + + private final ForwardProducer forwardProducer; + private final TopicRouteCache topicRouteCache; + + private ThreadPoolExecutor heartbeatExecutors; + private final Map/* cluster list */> groupClusterData = new ConcurrentHashMap<>(); + private TxHeartbeatServiceThread txHeartbeatServiceThread; + + public TransactionHeartbeatRegisterService(ForwardProducer forwardProducer, TopicRouteCache topicRouteCache) { + this.forwardProducer = forwardProducer; + this.topicRouteCache = topicRouteCache; + } + + public void addProducerGroup(String group, String topic) { + try { + MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(topic); + List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); + + if (brokerDataList != null) { + for (BrokerData brokerData : brokerDataList) { + groupClusterData.compute(group, (groupName, clusterDataSet) -> { + if (clusterDataSet == null) { + clusterDataSet = Sets.newHashSet(); + } + clusterDataSet.add(new ClusterData(brokerData.getCluster())); + return clusterDataSet; + }); + } + } + } catch (Exception e) { + log.error("add producer group err in txHeartBeat. groupId: {}, err: {}", group, e); + } + } + + public void onProducerGroupOffline(String group) { + groupClusterData.remove(group); + } + + public void scanProducerHeartBeat() { + Set groupSet = groupClusterData.keySet(); + + Map> clusterHeartbeatData = new HashMap<>(); + for (String group : groupSet) { + groupClusterData.computeIfPresent(group, (groupName, clusterDataSet) -> { + if (clusterDataSet.isEmpty()) { + return null; + } + + ProducerData producerData = new ProducerData(); + producerData.setGroupName(groupName); + + for (ClusterData clusterData : clusterDataSet) { + List heartbeatDataList = clusterHeartbeatData.get(clusterData.cluster); + if (heartbeatDataList == null) { + heartbeatDataList = new ArrayList<>(); + } + + HeartbeatData heartbeatData; + if (heartbeatDataList.isEmpty()) { + heartbeatData = new HeartbeatData(); + heartbeatData.setClientID(TRANS_HEARTBEAT_CLIENT_ID); + heartbeatDataList.add(heartbeatData); + } else { + heartbeatData = heartbeatDataList.get(heartbeatDataList.size() - 1); + if (heartbeatData.getProducerDataSet().size() >= ConfigurationManager.getProxyConfig().getTransactionHeartbeatBatchNum()) { + heartbeatData = new HeartbeatData(); + heartbeatData.setClientID(TRANS_HEARTBEAT_CLIENT_ID); + heartbeatDataList.add(heartbeatData); + } + } + + heartbeatData.getProducerDataSet().add(producerData); + clusterHeartbeatData.put(clusterData.cluster, heartbeatDataList); + } + + if (clusterDataSet.isEmpty()) { + return null; + } + return clusterDataSet; + }); + } + + if (clusterHeartbeatData.isEmpty()) { + return; + } + Set>> clusterEntry = clusterHeartbeatData.entrySet(); + for (Map.Entry> entry : clusterEntry) { + sendHeartBeatToCluster(entry.getKey(), entry.getValue()); + } + } + + protected void sendHeartBeatToCluster(String clusterName, List heartbeatDataList) { + if (heartbeatDataList == null) { + return; + } + for (HeartbeatData heartbeatData : heartbeatDataList) { + sendHeartBeatToCluster(clusterName, heartbeatData); + } + } + + protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData) { + try { + MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(clusterName); + List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); + if (brokerDataList == null) { + return; + } + for (BrokerData brokerData : brokerDataList) { + heartbeatExecutors.submit(() -> { + String brokerAddr = brokerData.selectBrokerAddr(); + try { + this.forwardProducer.heartBeat(brokerAddr, heartbeatData, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } catch (Exception e) { + log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, e); + } + }); + } + } catch (Exception e) { + log.error("get broker add in cluster failed in tx. clusterName: {}", clusterName, e); + } + } + + static class ClusterData { + private final String cluster; + + public ClusterData(String cluster) { + this.cluster = cluster; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ClusterData)) { + return super.equals(obj); + } + + ClusterData other = (ClusterData) obj; + return cluster.equals(other.cluster); + } + + @Override + public int hashCode() { + return cluster.hashCode(); + } + } + + class TxHeartbeatServiceThread extends ServiceThread { + + @Override + public String getServiceName() { + return TxHeartbeatServiceThread.class.getName(); + } + + @Override + public void run() { + while (!this.isStopped()) { + this.waitForRunning(TimeUnit.SECONDS.toMillis(ConfigurationManager.getProxyConfig().getTransactionHeartbeatPeriodSecond())); + } + } + + @Override + protected void onWaitEnd() { + scanProducerHeartBeat(); + } + } + + @Override + public void start() throws Exception { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + txHeartbeatServiceThread = new TxHeartbeatServiceThread(); + + txHeartbeatServiceThread.start(); + heartbeatExecutors = ThreadPoolMonitor.createAndMonitor( + proxyConfig.getTransactionHeartbeatThreadPoolNums(), + proxyConfig.getTransactionHeartbeatThreadPoolNums(), + 0L, TimeUnit.MILLISECONDS, + "TransactionHeartbeatRegisterThread", + proxyConfig.getTransactionHeartbeatThreadPoolQueueCapacity() + ); + } + + @Override + public void shutdown() throws Exception { + txHeartbeatServiceThread.shutdown(); + heartbeatExecutors.shutdown(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index c04cb82bb3..a4daec0139 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -39,15 +39,15 @@ public class TransactionId { private String brokerTransactionId; private long commitLogOffset; private long tranStateTableOffset; - private String gatewayTransactionId; + private String proxyTransactionId; public TransactionId(SocketAddress brokerAddr, String brokerTransactionId, long commitLogOffset, - long tranStateTableOffset, String gatewayTransactionId) { + long tranStateTableOffset, String proxyTransactionId) { this.brokerAddr = brokerAddr; this.brokerTransactionId = brokerTransactionId; this.commitLogOffset = commitLogOffset; this.tranStateTableOffset = tranStateTableOffset; - this.gatewayTransactionId = gatewayTransactionId; + this.proxyTransactionId = proxyTransactionId; } public TransactionId() { @@ -87,7 +87,7 @@ public class TransactionId { .brokerTransactionId(orgTransactionId) .commitLogOffset(commitLogOffset) .tranStateTableOffset(tranStateTableOffset) - .gatewayTransactionId(gatewayTransactionId) + .proxyTransactionId(gatewayTransactionId) .build(); } @@ -111,7 +111,7 @@ public class TransactionId { .brokerTransactionId(new String(orgTransactionIdByte, StandardCharsets.UTF_8)) .commitLogOffset(commitLogOffset) .tranStateTableOffset(tranStateTableOffset) - .gatewayTransactionId(transactionId) + .proxyTransactionId(transactionId) .build(); } @@ -124,12 +124,12 @@ public class TransactionId { return false; } TransactionId id = (TransactionId) o; - return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && Objects.equals(brokerAddr, id.brokerAddr) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && Objects.equals(gatewayTransactionId, id.gatewayTransactionId); + return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && Objects.equals(brokerAddr, id.brokerAddr) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && Objects.equals(proxyTransactionId, id.proxyTransactionId); } @Override public int hashCode() { - return Objects.hash(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, gatewayTransactionId); + return Objects.hash(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); } public static TransactionIdBuilder builder() { @@ -152,8 +152,8 @@ public class TransactionId { return this.tranStateTableOffset; } - public String getGatewayTransactionId() { - return this.gatewayTransactionId; + public String getProxyTransactionId() { + return this.proxyTransactionId; } public void setBrokerAddr(SocketAddress brokerAddr) { @@ -172,8 +172,8 @@ public class TransactionId { this.tranStateTableOffset = tranStateTableOffset; } - public void setGatewayTransactionId(String gatewayTransactionId) { - this.gatewayTransactionId = gatewayTransactionId; + public void setProxyTransactionId(String proxyTransactionId) { + this.proxyTransactionId = proxyTransactionId; } @Override @@ -183,7 +183,7 @@ public class TransactionId { ", brokerTransactionId='" + brokerTransactionId + '\'' + ", commitLogOffset=" + commitLogOffset + ", tranStateTableOffset=" + tranStateTableOffset + - ", gatewayTransactionId='" + gatewayTransactionId + '\'' + + ", gatewayTransactionId='" + proxyTransactionId + '\'' + '}'; } @@ -192,7 +192,7 @@ public class TransactionId { private String brokerTransactionId; private long commitLogOffset; private long tranStateTableOffset; - private String gatewayTransactionId; + private String proxyTransactionId; TransactionIdBuilder() { } @@ -217,13 +217,13 @@ public class TransactionId { return this; } - public TransactionIdBuilder gatewayTransactionId(String gatewayTransactionId) { - this.gatewayTransactionId = gatewayTransactionId; + public TransactionIdBuilder proxyTransactionId(String proxyTransactionId) { + this.proxyTransactionId = proxyTransactionId; return this; } public TransactionId build() { - return new TransactionId(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, gatewayTransactionId); + return new TransactionId(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); } @Override @@ -233,7 +233,7 @@ public class TransactionId { ", brokerTransactionId='" + brokerTransactionId + '\'' + ", commitLogOffset=" + commitLogOffset + ", tranStateTableOffset=" + tranStateTableOffset + - ", gatewayTransactionId='" + gatewayTransactionId + '\'' + + ", gatewayTransactionId='" + proxyTransactionId + '\'' + '}'; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index dfc8faa859..1bb090e809 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -34,8 +34,13 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); - private GrpcClientChannel() { + private final String group; + private final String clientId; + + private GrpcClientChannel(String group, String clientId) { super(ChannelManager.createSimpleChannelDirectly()); + this.group = group; + this.clientId = clientId; } public void addClientObserver(CompletableFuture future) { @@ -45,7 +50,7 @@ public class GrpcClientChannel extends SimpleChannel { public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), - GrpcClientChannel::new, + () -> new GrpcClientChannel(group, clientId), GrpcClientChannel.class); channelManager.addGroupClientId(group, clientId); @@ -104,4 +109,12 @@ public class GrpcClientChannel extends SimpleChannel { } return super.writeAndFlush(msg); } + + public String getGroup() { + return group; + } + + public String getClientId() { + return clientId; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 830fed4281..8db0a48d63 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -64,6 +64,8 @@ import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; @@ -72,6 +74,7 @@ import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,16 +92,17 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final RouteService routeService; private final ClientService clientService; private final PullMessageService pullMessageService; + private final TransactionService transactionService; public ClusterGrpcService() { this.channelManager = new ChannelManager(); - this.connectorManager = new ConnectorManager(checkData -> { - }); + this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.receiveMessageService = new ReceiveMessageService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(connectorManager); this.clientService = new ClientService(scheduledExecutorService); this.pullMessageService = new PullMessageService(connectorManager); + this.transactionService = new TransactionService(connectorManager, channelManager); this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); this.appendStartAndShutdown(this.connectorManager); @@ -158,7 +162,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - return null; + return this.transactionService.endTransaction(ctx, request); } @Override @@ -241,4 +245,12 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc scheduledExecutorService.shutdown(); } } + + private class GrpcTransactionStateChecker implements TransactionStateChecker { + + @Override + public void checkTransactionState(TransactionStateCheckRequest checkData) { + transactionService.checkTransactionState(checkData); + } + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index cc00a0968d..98b7f300d6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.Message; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; @@ -105,6 +106,14 @@ public class ProducerService extends BaseService { .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) .build(); } + + if (StringUtils.isNotBlank(sendResult.getTransactionId())) { + Message message = request.getMessage(); + String group = Converter.getResourceNameWithNamespace(message.getSystemAttribute().getProducerGroup()); + String topic = Converter.getResourceNameWithNamespace(message.getTopic()); + this.connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(group, topic); + } + return SendMessageResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java new file mode 100644 index 0000000000..5e6060a36d --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -0,0 +1,117 @@ +/* + * 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.grpc.service.cluster; + +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.ForwardProducer; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.common.ResponseHook; + +public class TransactionService extends BaseService implements TransactionStateChecker { + + private ChannelManager channelManager; + private final ForwardProducer forwardProducer; + + private volatile ResponseHook checkTransactionStateHook = null; + private volatile ResponseHook endTransactionHook = null; + + public TransactionService(ConnectorManager connectorManager, ChannelManager channelManager) { + super(connectorManager); + this.forwardProducer = connectorManager.getForwardProducer(); + this.channelManager = channelManager; + } + + @Override + public void checkTransactionState(TransactionStateCheckRequest checkData) { + try { + List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); + String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); + + GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); + String transactionId = checkData.getTransactionId().getProxyTransactionId(); + + Message message = Converter.buildMessage(checkData.getMessageExt()); + + PollCommandResponse commandResponse = PollCommandResponse.newBuilder() + .setRecoverOrphanedTransactionCommand( + RecoverOrphanedTransactionCommand.newBuilder() + .setOrphanedTransactionalMessage(message) + .setTransactionId(transactionId) + .build() + ).build(); + channel.writeAndFlush(commandResponse); + if (this.checkTransactionStateHook != null) { + this.checkTransactionStateHook.beforeResponse(checkData, commandResponse, null); + } + } catch (Throwable t) { + if (this.checkTransactionStateHook != null) { + this.checkTransactionStateHook.beforeResponse(checkData, null, t); + } + } + } + + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (endTransactionHook != null) { + endTransactionHook.beforeResponse(request, response, throwable); + } + }); + try { + EndTransactionRequestHeader requestHeader = this.convertToEndTransactionRequestHeader(ctx, request); + this.forwardProducer.endTransaction(requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + future.complete(EndTransactionResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected EndTransactionRequestHeader convertToEndTransactionRequestHeader(Context ctx, + EndTransactionRequest request) { + return Converter.buildEndTransactionRequestHeader(request); + } + + public void setCheckTransactionStateHook( + ResponseHook checkTransactionStateHook) { + this.checkTransactionStateHook = checkTransactionStateHook; + } + + public void setEndTransactionHook( + ResponseHook endTransactionHook) { + this.endTransactionHook = endTransactionHook; + } +} From b425608b1bf03a60a5ce0d565c8aecc45ba5cbc4 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Thu, 17 Mar 2022 20:08:37 +0800 Subject: [PATCH 044/338] [ISSUE #3949] Refactor partition generation and add unit test. --- .../grpc/service/ClusterGrpcService.java | 52 +--- .../grpc/service/cluster/RouteService.java | 58 ++-- .../service/cluster/RouteServiceTest.java | 257 +++++++----------- 3 files changed, 130 insertions(+), 237 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 8db0a48d63..be0368f9b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -17,47 +17,9 @@ package org.apache.rocketmq.proxy.grpc.service; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HealthCheckResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NoopCommand; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.NotifyClientTerminationResponse; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; -import apache.rocketmq.v1.ReportThreadStackTraceRequest; -import apache.rocketmq.v1.ReportThreadStackTraceResponse; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.*; import com.google.rpc.Code; import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.channel.ChannelManager; @@ -69,15 +31,14 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; -import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; -import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; -import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; +import org.apache.rocketmq.proxy.grpc.service.cluster.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); @@ -85,7 +46,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread")); private final ChannelManager channelManager; - private final ConnectorManager connectorManager; private final ProducerService producerService; private final ReceiveMessageService receiveMessageService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 2b4a34fc3b..ea8ad005fe 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -16,33 +16,25 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Assignment; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.Permission; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.*; import com.google.rpc.Code; import io.grpc.Context; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + public class RouteService extends BaseService { private volatile ParameterConverter queryRouteEndpointConverter; @@ -148,21 +140,33 @@ public class RouteService extends BaseService { r = queueData.getReadQueueNums(); } - for (int i = 0; i < (rw + r + w); i++) { - Partition.Builder builder = Partition.newBuilder() + // r here means readOnly queue nums, w means writeOnly queue nums, while rw means readable and writable queue nums. + int queueIdIndex = 0; + for(int i = 0; i < r; i++){ + Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.READ); + partitionList.add(partition); + } + + for(int i = 0; i < w; i++){ + Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.WRITE); + partitionList.add(partition); + } + + for (int i = 0; i < rw; i++) { + Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.READ_WRITE); + partitionList.add(partition); + } + + return partitionList; + } + + private static Partition buildPartition(Broker broker, Resource topic, int queueId, Permission perm) { + Partition.Builder builder = Partition.newBuilder() .setBroker(broker) .setTopic(topic) - .setId(i); - if (i < r) { - builder.setPermission(Permission.READ); - } else if (i < w) { - builder.setPermission(Permission.WRITE); - } else { - builder.setPermission(Permission.READ_WRITE); - } - partitionList.add(builder.build()); - } - return partitionList; + .setId(queueId); + builder.setPermission(perm); + return builder.build(); } public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 03a0439302..41851d9b8b 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -1,177 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Address; -import apache.rocketmq.v1.AddressScheme; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.Permission; import apache.rocketmq.v1.Resource; -import com.google.rpc.Code; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.when; +import java.util.List; -public class RouteServiceTest extends BaseServiceTest { +import static org.assertj.core.api.Assertions.assertThat; - @Override - public void beforeEach() throws Throwable { - TopicRouteData routeData = new TopicRouteData(); +public class RouteServiceTest { + public static final String BROKER_NAME = "brokerName"; + public static final String NAMESPACE = "namespace"; + public static final String TOPIC = "topic"; + public static final Broker MOCK_BROKER = Broker.newBuilder().setName(BROKER_NAME).build(); + public static final Resource MOCK_TOPIC = Resource.newBuilder() + .setName(TOPIC) + .setResourceNamespace(NAMESPACE) + .build(); - List brokerDataList = new ArrayList<>(); - BrokerData brokerData = new BrokerData(); - brokerData.setCluster("cluster"); - brokerData.setBrokerName("brokerName"); - HashMap brokerAddrs = new HashMap() {{ - put(0L, "127.0.0.1:10911"); - }}; - brokerData.setBrokerAddrs(brokerAddrs); - brokerDataList.add(brokerData); + @Before + public void before() throws Exception { + } - List queueDataList = new ArrayList<>(); + @After + public void after() throws Exception { + } + + + @Test + public void testGenPartitionFromQueueData() throws Exception { + // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. + QueueData queueDataWith8R8WPermRW = mockQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith8R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + assertThat(partitionWith8R8WPermRW.size()).isEqualTo(8); + assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(8); + assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); + assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); + + // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. + QueueData queueDataWith8R8WPermR = mockQueueData(8, 8, PermName.PERM_READ); + List partitionWith8R8WPermR = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); + assertThat(partitionWith8R8WPermR.size()).isEqualTo(8); + assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); + assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); + assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); + + // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. + QueueData queueDataWith8R8WPermW = mockQueueData(8, 8, PermName.PERM_WRITE); + List partitionWith8R8WPermW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); + assertThat(partitionWith8R8WPermW.size()).isEqualTo(8); + assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(8); + assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); + assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); + + // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. + QueueData queueDataWith8R0WPermRW = mockQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith8R0WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); + assertThat(partitionWith8R0WPermRW.size()).isEqualTo(8); + assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); + assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); + assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); + + // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. + QueueData queueDataWith4R8WPermRW = mockQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith4R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + assertThat(partitionWith4R8WPermRW.size()).isEqualTo(8); + assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(4); + assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(4); + assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); + + } + + private QueueData mockQueueData(int r, int w, int perm) { QueueData queueData = new QueueData(); - queueData.setPerm(6); - queueData.setWriteQueueNums(8); - queueData.setReadQueueNums(8); - queueData.setBrokerName("brokerName"); - queueDataList.add(queueData); - - routeData.setBrokerDatas(brokerDataList); - routeData.setQueueDatas(queueDataList); - - MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); - when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); - - when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + queueData.setBrokerName(BROKER_NAME); + queueData.setReadQueueNums(r); + queueData.setWriteQueueNums(w); + queueData.setPerm(perm); + return queueData; } - @Test - public void testQueryRouteWithInvalidEndpoints() { - RouteService routeService = new RouteService(this.clientManager); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .build()); - - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testQueryRoute() { - RouteService routeService = new RouteService(this.clientManager); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .build()); - - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(8, response.getPartitionsCount()); - assertEquals("host", response.getPartitions(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testQueryRouteWhenTopicNotExist() { - RouteService routeService = new RouteService(this.clientManager); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .setTopic(Resource.newBuilder() - .setName("notExistTopic") - .build()) - .build()); - - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testQueryAssignmentInvalidEndpoints() { - RouteService routeService = new RouteService(this.clientManager); - - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .build()); - - try { - QueryAssignmentResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testQueryAssignment() { - RouteService routeService = new RouteService(this.clientManager); - - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .setClientId("clientId") - .build()); - - try { - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); - assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } - } -} \ No newline at end of file +} From e44f29a64328f671ee26e3e14446d857f0a531e0 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 17 Mar 2022 17:25:49 +0800 Subject: [PATCH 045/338] [ISSUE #3949] forwardMsgToDLQ for cluster mode; add ProducerGroupOfflineListener --- .../client/ProducerGroupOfflineListener.java | 22 +++++++ .../broker/client/ProducerManager.java | 32 +++++++++- .../broker/client/ProducerManagerTest.java | 14 ++++- .../common/consumer/ReceiptHandle.java | 30 ++++++++- .../rocketmq/proxy/grpc/common/Converter.java | 8 +-- .../grpc/service/ClusterGrpcService.java | 34 +--------- .../grpc/service/cluster/ClientService.java | 51 ++++++++++++++- .../grpc/service/cluster/ProducerService.java | 63 ++++++++++++++++--- .../service/cluster/ProducerServiceTest.java | 2 +- 9 files changed, 202 insertions(+), 54 deletions(-) create mode 100644 broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java new file mode 100644 index 0000000000..1107f0d9ed --- /dev/null +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.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.broker.client; + +public interface ProducerGroupOfflineListener { + + void onOffline(String group); +} diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java index 11b9088831..09da153a96 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java @@ -40,6 +40,7 @@ public class ProducerManager { private final ConcurrentHashMap clientChannelTable = new ConcurrentHashMap<>(); protected final BrokerStatsManager brokerStatsManager; private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter(); + private volatile ProducerGroupOfflineListener producerGroupOfflineListener; public ProducerManager() { this.brokerStatsManager = null; @@ -63,8 +64,11 @@ public class ProducerManager { } public void scanNotActiveChannel() { - for (final Map.Entry> entry : this.groupChannelTable - .entrySet()) { + Iterator>> iterator = this.groupChannelTable.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + final String group = entry.getKey(); final ConcurrentHashMap chlMap = entry.getValue(); @@ -84,6 +88,12 @@ public class ProducerManager { RemotingUtil.closeChannel(info.getChannel()); } } + + if (chlMap.isEmpty()) { + log.warn("SCAN: remove expired channel from ProducerManager groupChannelTable, all clear, group={}", group); + iterator.remove(); + this.notifyProducerOffline(group); + } } } @@ -103,6 +113,13 @@ public class ProducerManager { log.info( "NETTY EVENT: remove channel[{}][{}] from ProducerManager groupChannelTable, producer group: {}", clientChannelInfo.toString(), remoteAddr, group); + if (clientChannelInfoTable.isEmpty()) { + ConcurrentHashMap oldGroupTable = this.groupChannelTable.remove(group); + if (oldGroupTable != null) { + log.info("unregister a producer group[{}] from groupChannelTable", group); + this.notifyProducerOffline(group); + } + } } } @@ -145,6 +162,7 @@ public class ProducerManager { if (channelTable.isEmpty()) { this.groupChannelTable.remove(group); + this.notifyProducerOffline(group); log.info("unregister a producer group[{}] from groupChannelTable", group); } } @@ -193,4 +211,14 @@ public class ProducerManager { public Channel findChannel(String clientId) { return clientChannelTable.get(clientId); } + + public void notifyProducerOffline(String group) { + if (this.producerGroupOfflineListener != null) { + this.producerGroupOfflineListener.onOffline(group); + } + } + + public void setProducerOfflineListener(ProducerGroupOfflineListener producerGroupOfflineListener) { + this.producerGroupOfflineListener = producerGroupOfflineListener; + } } diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java index 6c794ac5d3..3d05d39ef8 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java @@ -21,6 +21,7 @@ import io.netty.channel.ChannelFuture; import java.lang.reflect.Field; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Before; import org.junit.Test; @@ -50,6 +51,8 @@ public class ProducerManagerTest { @Test public void scanNotActiveChannel() throws Exception { producerManager.registerProducer(group, clientInfo); + AtomicReference groupRef = new AtomicReference<>(); + producerManager.setProducerOfflineListener(groupRef::set); assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNotNull(); assertThat(producerManager.findChannel("clientId")).isNotNull(); Field field = ProducerManager.class.getDeclaredField("CHANNEL_EXPIRED_TIMEOUT"); @@ -58,17 +61,21 @@ public class ProducerManagerTest { clientInfo.setLastUpdateTimestamp(System.currentTimeMillis() - CHANNEL_EXPIRED_TIMEOUT - 10); when(channel.close()).thenReturn(mock(ChannelFuture.class)); producerManager.scanNotActiveChannel(); - assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNull(); + assertThat(producerManager.getGroupChannelTable().get(group)).isNull(); + assertThat(groupRef.get()).isEqualTo(group); assertThat(producerManager.findChannel("clientId")).isNull(); } @Test public void doChannelCloseEvent() throws Exception { producerManager.registerProducer(group, clientInfo); + AtomicReference groupRef = new AtomicReference<>(); + producerManager.setProducerOfflineListener(groupRef::set); assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNotNull(); assertThat(producerManager.findChannel("clientId")).isNotNull(); producerManager.doChannelCloseEvent("127.0.0.1", channel); - assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNull(); + assertThat(producerManager.getGroupChannelTable().get(group)).isNull(); + assertThat(groupRef.get()).isEqualTo(group); assertThat(producerManager.findChannel("clientId")).isNull(); } @@ -86,6 +93,8 @@ public class ProducerManagerTest { @Test public void unregisterProducer() throws Exception { producerManager.registerProducer(group, clientInfo); + AtomicReference groupRef = new AtomicReference<>(); + producerManager.setProducerOfflineListener(groupRef::set); Map channelMap = producerManager.getGroupChannelTable().get(group); assertThat(channelMap).isNotNull(); assertThat(channelMap.get(channel)).isEqualTo(clientInfo); @@ -95,6 +104,7 @@ public class ProducerManagerTest { producerManager.unregisterProducer(group, clientInfo); channelMap = producerManager.getGroupChannelTable().get(group); channel1 = producerManager.findChannel("clientId"); + assertThat(groupRef.get()).isEqualTo(group); assertThat(channelMap).isNull(); assertThat(channel1).isNull(); diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java index b05db4602c..20f573e514 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.List; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; public class ReceiptHandle { private static final String SEPARATOR = MessageConst.KEY_SEPARATOR; @@ -35,6 +36,7 @@ public class ReceiptHandle { private final String brokerName; private final int queueId; private final long offset; + private final long commitLogOffset; private final String receiptHandle; public String encode() { @@ -42,7 +44,17 @@ public class ReceiptHandle { if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { t = RETRY_TOPIC; } - return startOffset + SEPARATOR + retrieveTime + SEPARATOR + invisibleTime + SEPARATOR + reviveQueueId + SEPARATOR + t + SEPARATOR + brokerName + SEPARATOR + queueId + SEPARATOR + offset; + return startOffset + SEPARATOR + retrieveTime + SEPARATOR + invisibleTime + SEPARATOR + reviveQueueId + + SEPARATOR + t + SEPARATOR + brokerName + SEPARATOR + queueId + SEPARATOR + offset + SEPARATOR + + commitLogOffset; + } + + public static ReceiptHandle create(MessageExt messageExt) { + String ckInfo = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (ckInfo == null) { + return null; + } + return decode(ckInfo + SEPARATOR + messageExt.getCommitLogOffset()); } public boolean isExpired() { @@ -62,6 +74,11 @@ public class ReceiptHandle { String brokerName = dataList.get(5); int queueId = Integer.parseInt(dataList.get(6)); long offset = Long.parseLong(dataList.get(7)); + long commitLogOffset = -1L; + if (dataList.size() >= 9) { + commitLogOffset = Long.parseLong(dataList.get(8)); + } + return new ReceiptHandleBuilder() .startOffset(startOffset) .retrieveTime(retrieveTime) @@ -72,12 +89,13 @@ public class ReceiptHandle { .queueId(queueId) .offset(offset) .nextVisibleTime(retrieveTime + invisibleTime) + .commitLogOffset(commitLogOffset) .receiptHandle(receiptHandle).build(); } ReceiptHandle(final long startOffset, final long retrieveTime, final long invisibleTime, final long nextVisibleTime, final int reviveQueueId, final String topic, final String brokerName, final int queueId, final long offset, - final String receiptHandle) { + final long commitLogOffset, final String receiptHandle) { this.startOffset = startOffset; this.retrieveTime = retrieveTime; this.invisibleTime = invisibleTime; @@ -87,6 +105,7 @@ public class ReceiptHandle { this.brokerName = brokerName; this.queueId = queueId; this.offset = offset; + this.commitLogOffset = commitLogOffset; this.receiptHandle = receiptHandle; } @@ -168,7 +187,8 @@ public class ReceiptHandle { } public ReceiptHandle build() { - return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.nextVisibleTime, this.reviveQueueId, this.topic, this.brokerName, this.queueId, this.offset, this.receiptHandle); + return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.nextVisibleTime, + this.reviveQueueId, this.topic, this.brokerName, this.queueId, this.offset, this.commitLogOffset, this.receiptHandle); } @java.lang.Override @@ -217,6 +237,10 @@ public class ReceiptHandle { return this.offset; } + public long getCommitLogOffset() { + return commitLogOffset; + } + public String getReceiptHandle() { return this.receiptHandle; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index e6b84a9ac3..e995df8491 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -197,7 +197,7 @@ public class Converter { ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getOffset()); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); consumerSendMsgBackRequestHeader.setGroup(groupName); consumerSendMsgBackRequestHeader.setDelayLevel(-1); consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); @@ -574,9 +574,9 @@ public class Converter { } // receipt_handle && invisible_period - String ckInfo = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); - if (ckInfo != null) { - systemAttributeBuilder.setReceiptHandle(ckInfo); + ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); + if (receiptHandle != null) { + systemAttributeBuilder.setReceiptHandle(receiptHandle.encode()); } // partition_id diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index be0368f9b4..8135f13f75 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -60,7 +60,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.receiveMessageService = new ReceiveMessageService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(connectorManager); - this.clientService = new ClientService(scheduledExecutorService); + this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); @@ -117,7 +117,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return null; + return this.producerService.forwardMessageToDeadLetterQueue(ctx, request); } @Override @@ -137,35 +137,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - CompletableFuture future = new CompletableFuture<>(); - String clientId = request.getClientId(); - PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand(NoopCommand.newBuilder().build()).build(); - - switch (request.getGroupCase()) { - case PRODUCER_GROUP: - Resource producerGroup = request.getProducerGroup(); - String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); - GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(this.channelManager, producerGroupName, clientId); - if (producerChannel == null) { - future.complete(noopCommandResponse); - } else { - producerChannel.addClientObserver(future); - } - break; - case CONSUMER_GROUP: - Resource consumerGroup = request.getConsumerGroup(); - String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); - GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(this.channelManager, consumerGroupName, clientId); - if (consumerChannel == null) { - future.complete(noopCommandResponse); - } else { - consumerChannel.addClientObserver(future); - } - break; - default: - break; - } - return future; + return this.clientService.pollCommand(ctx, request); } @Override public CompletableFuture reportThreadStackTrace(Context ctx, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index 44acde7df0..2eef9a38d7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -18,8 +18,13 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; import apache.rocketmq.v1.ConsumerData; import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.NoopCommand; import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.Resource; import io.grpc.Context; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ClientChannelInfo; @@ -27,6 +32,8 @@ import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; @@ -34,16 +41,22 @@ import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ClientService { +public class ClientService extends BaseService { private static final Logger log = LoggerFactory.getLogger(ClientService.class); + private final ChannelManager channelManager; private final ConsumerManager consumerManager = new ConsumerManager((event, group, args) -> { }); - private final ProducerManager producerManager = new ProducerManager(); + private final ProducerManager producerManager; - public ClientService(ScheduledExecutorService scheduledExecutorService) { + public ClientService(ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager) { + super(connectorManager); scheduledExecutorService.scheduleWithFixedDelay(this::scanNotActiveChannel, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); + this.channelManager = channelManager; + + this.producerManager = new ProducerManager(); + this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); } public void heartbeat(Context ctx, HeartbeatRequest request, ChannelManager channelManager) { @@ -96,6 +109,38 @@ public class ClientService { } } + public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { + CompletableFuture future = new CompletableFuture<>(); + String clientId = request.getClientId(); + PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand(NoopCommand.newBuilder().build()).build(); + + switch (request.getGroupCase()) { + case PRODUCER_GROUP: + Resource producerGroup = request.getProducerGroup(); + String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); + GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(this.channelManager, producerGroupName, clientId); + if (producerChannel == null) { + future.complete(noopCommandResponse); + } else { + producerChannel.addClientObserver(future); + } + break; + case CONSUMER_GROUP: + Resource consumerGroup = request.getConsumerGroup(); + String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); + GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(this.channelManager, consumerGroupName, clientId); + if (consumerChannel == null) { + future.complete(noopCommandResponse); + } else { + consumerChannel.addClientObserver(future); + } + break; + default: + break; + } + return future; + } + private void scanNotActiveChannel() { try { this.consumerManager.scanNotActiveChannel(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 98b7f300d6..bcf949f872 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -16,6 +16,8 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; @@ -26,6 +28,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; @@ -34,34 +38,42 @@ import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + public class ProducerService extends BaseService { private volatile ProducerQueueSelector messageQueueSelector; - private volatile ResponseHook producerServiceHook = null; + private volatile ResponseHook sendMessageHook = null; + private volatile ResponseHook forwardMessageToDLQHook = null; public ProducerService(ConnectorManager connectorManager) { super(connectorManager); messageQueueSelector = new DefaultProducerQueueSelector(this.connectorManager.getTopicRouteCache()); } - public void setProducerServiceHook(ResponseHook producerServiceHook) { - this.producerServiceHook = producerServiceHook; + public void setSendMessageHook(ResponseHook sendMessageHook) { + this.sendMessageHook = sendMessageHook; } public void setMessageQueueSelector(ProducerQueueSelector messageQueueSelector) { this.messageQueueSelector = messageQueueSelector; } + public void setForwardMessageToDLQHook( + ResponseHook forwardMessageToDLQHook) { + this.forwardMessageToDLQHook = forwardMessageToDLQHook; + } + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { - if (producerServiceHook != null) { - producerServiceHook.beforeResponse(request, response, throwable); + if (sendMessageHook != null) { + sendMessageHook.beforeResponse(request, response, throwable); } }); try { - Pair requestPair = this.convert(ctx, request); + Pair requestPair = this.convertSendMessageRequest(ctx, request); SendMessageRequestHeader requestHeader = requestPair.getLeft(); org.apache.rocketmq.common.message.Message message = requestPair.getRight(); SelectableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); @@ -96,11 +108,13 @@ public class ProducerService extends BaseService { return future; } - protected Pair convert(Context ctx, SendMessageRequest request) { + protected Pair convertSendMessageRequest( + Context ctx, SendMessageRequest request) { return Pair.of(Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); } - protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult sendResult) { + protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, + SendResult sendResult) { if (sendResult.getSendStatus() != SendStatus.SEND_OK) { return SendMessageResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) @@ -120,4 +134,37 @@ public class ProducerService extends BaseService { .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) .build(); } + + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (forwardMessageToDLQHook != null) { + forwardMessageToDLQHook.beforeResponse(request, response, throwable); + } + }); + try { + ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); + ConsumerSendMsgBackRequestHeader requestHeader = this.convertToConsumerSendMsgBackRequestHeader(ctx, request); + CompletableFuture resultFuture = this.connectorManager.getForwardProducer() + .sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + resultFuture.thenAccept(result -> { + future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) + .build()); + }).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackRequestHeader(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + return Converter.buildConsumerSendMsgBackRequestHeader(request); + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 2653ed31d2..3d00c3dbbd 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -149,7 +149,7 @@ public class ProducerServiceTest extends BaseServiceTest { producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> { throw ex; }); - producerService.setProducerServiceHook((request, response, t) -> { + producerService.setSendMessageHook((request, response, t) -> { assertSame(ex, t); }); From 7f4b7bce2df26aa2497bd7ce97064b41a6f835b5 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Thu, 17 Mar 2022 21:28:39 +0800 Subject: [PATCH 046/338] [ISSUE #3949] Do refactor work for passing check style. --- .../grpc/service/ClusterGrpcService.java | 54 +++++++++++++++---- .../grpc/service/cluster/ClientService.java | 8 +-- .../grpc/service/cluster/ProducerService.java | 17 +++--- .../service/cluster/PullMessageService.java | 51 +++++++++--------- .../cluster/ReceiveMessageService.java | 53 +++++++++--------- .../grpc/service/cluster/RouteService.java | 41 ++++++++------ 6 files changed, 138 insertions(+), 86 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 8135f13f75..7479cabf46 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -17,7 +17,40 @@ package org.apache.rocketmq.proxy.grpc.service; -import apache.rocketmq.v1.*; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HealthCheckResponse; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.HeartbeatResponse; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.PollCommandRequest; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; +import apache.rocketmq.v1.ReportThreadStackTraceRequest; +import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; import org.apache.rocketmq.common.ThreadFactoryImpl; @@ -28,10 +61,13 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.service.cluster.*; +import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; +import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; +import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,7 +152,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { + ForwardMessageToDeadLetterQueueRequest request) { return this.producerService.forwardMessageToDeadLetterQueue(ctx, request); } @@ -141,19 +177,19 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc } @Override public CompletableFuture reportThreadStackTrace(Context ctx, - ReportThreadStackTraceRequest request) { + ReportThreadStackTraceRequest request) { return null; } @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, - ReportMessageConsumptionResultRequest request) { + ReportMessageConsumptionResultRequest request) { return null; } @Override public CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request) { + NotifyClientTerminationRequest request) { this.clientService.unregister(ctx, request, channelManager); return CompletableFuture.completedFuture(NotifyClientTerminationResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) @@ -161,7 +197,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc } @Override public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { + ChangeInvisibleDurationRequest request) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index 2eef9a38d7..95fa09acf3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -24,16 +24,12 @@ import apache.rocketmq.v1.PollCommandRequest; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.Resource; import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; @@ -41,6 +37,10 @@ import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + public class ClientService extends BaseService { private static final Logger log = LoggerFactory.getLogger(ClientService.class); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index bcf949f872..1ee3d36c9d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -23,7 +23,6 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; -import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; @@ -31,15 +30,17 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import java.util.concurrent.CompletableFuture; + public class ProducerService extends BaseService { private volatile ProducerQueueSelector messageQueueSelector; @@ -149,14 +150,12 @@ public class ProducerService extends BaseService { ConsumerSendMsgBackRequestHeader requestHeader = this.convertToConsumerSendMsgBackRequestHeader(ctx, request); CompletableFuture resultFuture = this.connectorManager.getForwardProducer() .sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - resultFuture.thenAccept(result -> { - future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() + resultFuture.thenAccept(result -> future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) - .build()); - }).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + .build())).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index e406410ffa..587059b38b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -26,10 +26,6 @@ import apache.rocketmq.v1.QueryOffsetResponse; import com.google.protobuf.util.Timestamps; import com.google.rpc.Code; import io.grpc.Context; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.message.MessageExt; @@ -45,6 +41,11 @@ import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + public class PullMessageService extends BaseService { private final DefaultForwardClient defaultForwardClient; @@ -82,15 +83,13 @@ public class PullMessageService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, brokerName); offsetFuture = this.defaultForwardClient.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } - offsetFuture.thenAccept(result -> { - future.complete(QueryOffsetResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setOffset(result) - .build()); - }).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + offsetFuture.thenAccept(result -> future.complete(QueryOffsetResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setOffset(result) + .build())).exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } @@ -104,6 +103,7 @@ public class PullMessageService extends BaseService { pullMessageHook.beforeResponse(request, response, throwable); } }); + try { PullMessageRequestHeader requestHeader = this.convertToPullMessageRequestHeader(ctx, request); @@ -111,17 +111,20 @@ public class PullMessageService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, brokerName); CompletableFuture pullResultFuture = this.connectorManager.getForwardReadConsumer() - .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - pullResultFuture.thenAccept(pullResult -> { - try { - future.complete(convertToPullMessageResponse(ctx, request, pullResult)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + pullResultFuture + .thenAccept(pullResult -> { + try { + future.complete(convertToPullMessageResponse(ctx, request, pullResult)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java index 0019656611..ffd91a14c3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java @@ -25,10 +25,6 @@ import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import com.google.rpc.Code; import io.grpc.Context; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; @@ -48,6 +44,11 @@ import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + public class ReceiveMessageService extends BaseService { private final ForwardReadConsumer readConsumer; @@ -147,16 +148,18 @@ public class ReceiveMessageService extends BaseService { AckMessageRequestHeader requestHeader = this.convertToAckMessageRequestHeader(ctx, request); CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - ackResultFuture.thenAccept(result -> { - try { - future.complete(convertToAckMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + ackResultFuture + .thenAccept(result -> { + try { + future.complete(convertToAckMessageResponse(ctx, request, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } @@ -192,16 +195,18 @@ public class ReceiveMessageService extends BaseService { ChangeInvisibleTimeRequestHeader requestHeader = this.convertToChangeInvisibleTimeRequestHeader(ctx, request); CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - resultFuture.thenAccept(result -> { - try { - future.complete(convertToNackMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + resultFuture + .thenAccept(result -> { + try { + future.complete(convertToNackMessageResponse(ctx, request, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index ea8ad005fe..4adde9ea49 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -16,7 +16,16 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.*; +import apache.rocketmq.v1.Assignment; +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Endpoints; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.Permission; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.Resource; import com.google.rpc.Code; import io.grpc.Context; import org.apache.rocketmq.common.constant.PermName; @@ -140,35 +149,35 @@ public class RouteService extends BaseService { r = queueData.getReadQueueNums(); } - // r here means readOnly queue nums, w means writeOnly queue nums, while rw means readable and writable queue nums. + // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. int queueIdIndex = 0; - for(int i = 0; i < r; i++){ - Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.READ); + for (int i = 0; i < r; i++) { + Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ) + .build(); partitionList.add(partition); } - for(int i = 0; i < w; i++){ - Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.WRITE); + for (int i = 0; i < w; i++) { + Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.WRITE) + .build(); partitionList.add(partition); } for (int i = 0; i < rw; i++) { - Partition partition = buildPartition(broker, topic, queueIdIndex++, Permission.READ_WRITE); + Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ_WRITE) + .build(); partitionList.add(partition); } return partitionList; } - private static Partition buildPartition(Broker broker, Resource topic, int queueId, Permission perm) { - Partition.Builder builder = Partition.newBuilder() - .setBroker(broker) - .setTopic(topic) - .setId(queueId); - builder.setPermission(perm); - return builder.build(); - } - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { From d0ed25e933a36004f2d0d963ab8878b2f9e80f9a Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 17 Mar 2022 15:31:14 +0800 Subject: [PATCH 047/338] [ISSUE #3949] Implement route in Local mode --- .../rocketmq/proxy/grpc/common/ProxyMode.java | 14 ++ .../grpc/service/ClusterGrpcService.java | 10 +- .../proxy/grpc/service/LocalGrpcService.java | 12 +- .../grpc/service/cluster/RouteService.java | 172 +++++++++---- .../service/cluster/RouteServiceTest.java | 238 ++++++++++++++++-- 5 files changed, 377 insertions(+), 69 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java index acf8ea32c6..25ac8665f6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java @@ -34,10 +34,24 @@ public enum ProxyMode { return CLUSTER.mode.equals(mode.toUpperCase()); } + public static boolean isClusterMode(ProxyMode mode) { + if (mode == null) { + return false; + } + return CLUSTER.equals(mode); + } + public static boolean isLocalMode(String mode) { if (mode == null) { return false; } return LOCAL.mode.equals(mode.toUpperCase()); } + + public static boolean isLocalMode(ProxyMode mode) { + if (mode == null) { + return false; + } + return LOCAL.equals(mode); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 7479cabf46..03d63b6f11 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -53,6 +53,9 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.channel.ChannelManager; @@ -61,6 +64,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; @@ -71,10 +75,6 @@ import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); @@ -95,7 +95,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.receiveMessageService = new ReceiveMessageService(connectorManager); this.producerService = new ProducerService(connectorManager); - this.routeService = new RouteService(connectorManager); + this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 74b1349acc..2f5a1c86b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -77,6 +77,7 @@ import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; @@ -85,7 +86,9 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHand import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; @@ -98,14 +101,18 @@ public class LocalGrpcService implements GrpcForwardService { private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; + private final RouteService routeService; public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; this.channelManager = new ChannelManager(); + // TransactionStateChecker is not used in Local mode. + ConnectorManager connectorManager = new ConnectorManager(null); + this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return null; + return this.routeService.queryRoute(ctx, request); } @Override @@ -188,7 +195,7 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return null; + return this.routeService.queryAssignment(ctx, request); } @Override @@ -376,6 +383,7 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture reportThreadStackTrace(Context ctx, ReportThreadStackTraceRequest request) { + String commandId = request.getCommandId(); return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 4adde9ea49..c551135e9d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -16,6 +16,8 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.Address; +import apache.rocketmq.v1.AddressScheme; import apache.rocketmq.v1.Assignment; import apache.rocketmq.v1.Broker; import apache.rocketmq.v1.Endpoints; @@ -26,9 +28,17 @@ import apache.rocketmq.v1.QueryAssignmentResponse; import apache.rocketmq.v1.QueryRouteRequest; import apache.rocketmq.v1.QueryRouteResponse; import apache.rocketmq.v1.Resource; +import com.google.common.base.Preconditions; +import com.google.common.net.HostAndPort; import com.google.rpc.Code; import io.grpc.Context; +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.common.constant.PermName; +import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -37,14 +47,12 @@ import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - public class RouteService extends BaseService { + private final ProxyMode mode; private volatile ParameterConverter queryRouteEndpointConverter; private volatile ResponseHook queryRouteHook = null; @@ -53,9 +61,10 @@ public class RouteService extends BaseService { private volatile RouteAssignmentQueueSelector assignmentQueueSelector; private volatile ResponseHook queryAssignmentHook = null; - public RouteService(ConnectorManager connectorManager) { + public RouteService(ProxyMode mode, ConnectorManager connectorManager) { super(connectorManager); - + Preconditions.checkArgument(ProxyMode.isClusterMode(mode) || ProxyMode.isLocalMode(mode)); + this.mode = mode; queryRouteEndpointConverter = (ctx, parameter) -> parameter; queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; assignmentQueueSelector = new DefaultRouteAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); @@ -92,30 +101,47 @@ public class RouteService extends BaseService { }); try { - Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); - if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { - future.complete(QueryRouteResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + - request.getEndpoints() + " is invalidate")) - .build()); - return future; - } - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); + List brokerDataList = topicRouteData.getBrokerDatas(); List partitionList = new ArrayList<>(); - for (QueueData queueData : queueDataList) { - Broker broker = Broker.newBuilder() - .setName(queueData.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); + if (ProxyMode.isClusterMode(mode.name())) { + Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); + if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + future.complete(QueryRouteResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + request.getEndpoints() + " is invalidate")) + .build()); + return future; + } + for (QueueData queueData : queueDataList) { + Broker broker = Broker.newBuilder() + .setName(queueData.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); - partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + } } + if (ProxyMode.isLocalMode(mode.name())) { + Map> brokerMap = buildBrokerMap(brokerDataList); + + for (QueueData queueData : queueDataList) { + String brokerName = queueData.getBrokerName(); + Map brokerIdMap = brokerMap.get(brokerName); + if (brokerIdMap == null) { + break; + } + for (Broker broker : brokerIdMap.values()) { + partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + } + } + } + QueryRouteResponse response = QueryRouteResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .addAllPartitions(partitionList) @@ -187,36 +213,60 @@ public class RouteService extends BaseService { }); try { - Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); - if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { - future.complete(QueryAssignmentResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + - request.getEndpoints() + " is invalidate")) - .build()); - return future; - } - List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); + if (ProxyMode.isLocalMode(mode)) { + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() + .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); + Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); + for (SelectableMessageQueue messageQueue : messageQueueList) { + Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); + if (brokerIdMap != null) { + Broker broker = brokerIdMap.get(0L); - for (SelectableMessageQueue messageQueue : messageQueueList) { - Broker broker = Broker.newBuilder() - .setName(messageQueue.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); + Partition defaultPartition = Partition.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(Permission.READ_WRITE) + .setBroker(broker) + .build(); - Partition defaultPartition = Partition.newBuilder() - .setTopic(request.getTopic()) - .setId(-1) - .setPermission(Permission.READ_WRITE) - .setBroker(broker) - .build(); - - assignments.add(Assignment.newBuilder() - .setPartition(defaultPartition) - .build()); + assignments.add(Assignment.newBuilder() + .setPartition(defaultPartition) + .build()); + } + } } + if (ProxyMode.isClusterMode(mode)) { + Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); + if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { + future.complete(QueryAssignmentResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + request.getEndpoints() + " is invalidate")) + .build()); + return future; + } + for (SelectableMessageQueue messageQueue : messageQueueList) { + Broker broker = Broker.newBuilder() + .setName(messageQueue.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); + + Partition defaultPartition = Partition.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(Permission.READ_WRITE) + .setBroker(broker) + .build(); + + assignments.add(Assignment.newBuilder() + .setPartition(defaultPartition) + .build()); + } + } + QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() .addAllAssignments(assignments) .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) @@ -227,4 +277,32 @@ public class RouteService extends BaseService { } return future; } + + private Map> buildBrokerMap(List brokerDataList) { + Map> brokerMap = new HashMap<>(); + for (BrokerData brokerData : brokerDataList) { + Map brokerIdMap = new HashMap<>(); + String brokerName = brokerData.getBrokerName(); + for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { + Long brokerId = entry.getKey(); + HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); + Broker broker = Broker.newBuilder() + .setName(brokerName) + .setId(Math.toIntExact(brokerId)) + .setEndpoints(Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses( + Address.newBuilder() + .setPort(hostAndPort.getPort()) + .setHost(hostAndPort.getHost()) + ) + .build()) + .build(); + + brokerIdMap.put(brokerId, broker); + } + brokerMap.put(brokerName, brokerIdMap); + } + return brokerMap; + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 41851d9b8b..73761cd9b3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -17,39 +17,66 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.Address; +import apache.rocketmq.v1.AddressScheme; import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Endpoints; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.Permission; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; import apache.rocketmq.v1.Resource; +import com.google.common.net.HostAndPort; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; -import org.junit.After; -import org.junit.Before; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.junit.Test; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; -public class RouteServiceTest { +public class RouteServiceTest extends BaseServiceTest { + private String brokerAddress = "127.0.0.1:10911"; public static final String BROKER_NAME = "brokerName"; public static final String NAMESPACE = "namespace"; public static final String TOPIC = "topic"; public static final Broker MOCK_BROKER = Broker.newBuilder().setName(BROKER_NAME).build(); public static final Resource MOCK_TOPIC = Resource.newBuilder() - .setName(TOPIC) - .setResourceNamespace(NAMESPACE) - .build(); + .setName(TOPIC) + .setResourceNamespace(NAMESPACE) + .build(); - @Before - public void before() throws Exception { + @Override + public void beforeEach() { + List brokerDataList = new ArrayList<>(); + BrokerData brokerData = new BrokerData(); + brokerData.setCluster("cluster"); + brokerData.setBrokerName("brokerName"); + HashMap brokerAddrs = new HashMap() {{ + put(0L, brokerAddress); + }}; + brokerData.setBrokerAddrs(brokerAddrs); + brokerDataList.add(brokerData); + + List queueDataList = new ArrayList<>(); + QueueData queueData = new QueueData(); + queueData.setPerm(6); + queueData.setWriteQueueNums(8); + queueData.setReadQueueNums(8); + queueData.setBrokerName("brokerName"); + queueDataList.add(queueData); } - @After - public void after() throws Exception { - } - - @Test public void testGenPartitionFromQueueData() throws Exception { // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. @@ -103,4 +130,185 @@ public class RouteServiceTest { return queueData; } + @Test + public void testLocalModeQueryRoute() { + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.clientManager); + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()); + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(8, response.getPartitionsCount()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getPartitions(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRouteWithInvalidEndpoints() { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRoute() { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(8, response.getPartitionsCount()); + assertEquals("host", response.getPartitions(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryRouteWhenTopicNotExist() { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("notExistTopic") + .build()) + .build()); + + try { + QueryRouteResponse response = future.get(); + assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryAssignmentInvalidEndpoints() { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setTopic( + Resource.newBuilder() + .setName("topic") + .build() + ) + .build()); + + try { + QueryAssignmentResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testLocalModeQueryAssignment() { + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.clientManager); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setClientId("clientId") + .build()); + + try { + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } + + @Test + public void testQueryAssignment() { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setEndpoints(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setClientId("clientId") + .build()); + + try { + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); + assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); + } catch (Exception e) { + assertNull(e); + } + } + } From 806def231b3897518182f9c5e054de3e9b70a49b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 17 Mar 2022 17:05:20 +0800 Subject: [PATCH 048/338] [ISSUE #3949] Support PollCommand Support reportMessageConsumptionResult Support reportThreadStackTrace --- .../adapter/channel/GrpcClientChannel.java | 34 ++++++++++--- .../rocketmq/proxy/grpc/common/Converter.java | 44 ++++++++++++++++- .../common/PollCommandResponseFuture.java | 41 ++++++++++++++++ .../common/PollCommandResponseManager.java | 37 ++++++++++++++ .../proxy/grpc/common/ResponseBuilder.java | 11 +++++ .../grpc/service/ClusterGrpcService.java | 5 +- .../proxy/grpc/service/LocalGrpcService.java | 49 +++++++++++++++++-- .../grpc/service/cluster/ClientService.java | 9 ++-- 8 files changed, 213 insertions(+), 17 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index 1bb090e809..99ab1da516 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.PrintThreadStackTraceCommand; import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; import io.netty.channel.ChannelFuture; import java.nio.ByteBuffer; @@ -26,9 +27,11 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { @@ -36,21 +39,23 @@ public class GrpcClientChannel extends SimpleChannel { private final String group; private final String clientId; + private final PollCommandResponseManager manager; - private GrpcClientChannel(String group, String clientId) { + private GrpcClientChannel(String group, String clientId, PollCommandResponseManager manager) { super(ChannelManager.createSimpleChannelDirectly()); this.group = group; this.clientId = clientId; + this.manager = manager; } public void addClientObserver(CompletableFuture future) { this.pollCommandResponseFutureRef.set(future); } - public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId) { + public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId, PollCommandResponseManager manager) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), - () -> new GrpcClientChannel(group, clientId), + () -> new GrpcClientChannel(group, clientId, manager), GrpcClientChannel.class); channelManager.addGroupClientId(group, clientId); @@ -89,12 +94,25 @@ public class GrpcClientChannel extends SimpleChannel { final CheckTransactionStateRequestHeader requestHeader = (CheckTransactionStateRequestHeader) command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); - RecoverOrphanedTransactionCommand recoverOrphanedTransactionCommand = RecoverOrphanedTransactionCommand.newBuilder() - .setTransactionId(requestHeader.getTransactionId()) - .setOrphanedTransactionalMessage(Converter.buildMessage(messageExt)) - .build(); future.complete(PollCommandResponse.newBuilder() - .setRecoverOrphanedTransactionCommand(recoverOrphanedTransactionCommand) + .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() + .setTransactionId(requestHeader.getTransactionId()) + .setOrphanedTransactionalMessage(Converter.buildMessage(messageExt)) + .build()) + .build()); + break; + } + case RequestCode.GET_CONSUMER_RUNNING_INFO: { + final GetConsumerRunningInfoRequestHeader requestHeader = + (GetConsumerRunningInfoRequestHeader) command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); + if (!requestHeader.isJstackEnable()) { + break; + } + String commandId = manager.putResponse(command.getOpaque()); + future.complete(PollCommandResponse.newBuilder() + .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() + .setCommandId(commandId) + .build()) .build()); break; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index e995df8491..4c276ee6cc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.grpc.common; import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; import apache.rocketmq.v1.ConsumeMessageType; import apache.rocketmq.v1.ConsumeModel; import apache.rocketmq.v1.ConsumePolicy; @@ -37,6 +38,7 @@ import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.ProducerData; import apache.rocketmq.v1.PullMessageRequest; import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SubscriptionEntry; @@ -68,6 +70,8 @@ import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; @@ -185,7 +189,24 @@ public class Converter { changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(handle.getInvisibleTime()); + changeInvisibleTimeRequestHeader.setInvisibleTime(0L); + return changeInvisibleTimeRequestHeader; + } + + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader( + ChangeInvisibleDurationRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String receiptHandleStr = request.getReceiptHandle(); + ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(topicName); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); return changeInvisibleTimeRequestHeader; } @@ -619,4 +640,25 @@ public class Converter { } } + public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult( + ReportMessageConsumptionResultRequest request) { + ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); + switch (request.getStatus().getCode()) { + case Code.OK_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); + break; + } + case Code.INTERNAL_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); + break; + } + case Code.INVALID_ARGUMENT_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); + break; + } + } + consumeMessageDirectlyResult.setRemark("From gRPC client"); + return consumeMessageDirectlyResult; + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java new file mode 100644 index 0000000000..122077b542 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.common; + +public class PollCommandResponseFuture { + private final String commandId; + private final Integer opaque; + + public PollCommandResponseFuture(String commandId, int opaque) { + this.commandId = commandId; + this.opaque = opaque; + } + + public PollCommandResponseFuture(String commandId) { + this.commandId = commandId; + this.opaque = null; + } + + public String getCommandId() { + return commandId; + } + + public Integer getOpaque() { + return opaque; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java new file mode 100644 index 0000000000..0311788756 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.common; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + +public class PollCommandResponseManager { + private final ConcurrentMap futureTable = new ConcurrentHashMap<>(); + private final AtomicLong commandIdGenerator = new AtomicLong(0); + + public String putResponse(int opaque) { + String commandId = String.valueOf(commandIdGenerator.incrementAndGet()); + futureTable.put(commandId, new PollCommandResponseFuture(commandId, opaque)); + return commandId; + } + + public PollCommandResponseFuture getResponse(String commandId) { + return futureTable.get(commandId); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java index 25eddefd7b..7902014e02 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java @@ -50,6 +50,17 @@ public class ResponseBuilder { .build(); } + public static ResponseCommon buildSuccessCommon() { + Status status = Status.newBuilder() + .setCode(Code.OK.getNumber()) + .setMessage("ok") + .build(); + + return ResponseCommon.newBuilder() + .setStatus(status) + .build(); + } + public static HeartbeatResponse buildHeartbeatResponse(RemotingCommand command) { return HeartbeatResponse.newBuilder() .setCommon(buildCommon(command.getCode(), command.getRemark())) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 03d63b6f11..304e4598e2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -64,6 +64,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; @@ -89,14 +90,16 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ClientService clientService; private final PullMessageService pullMessageService; private final TransactionService transactionService; + private final PollCommandResponseManager pollCommandResponseManager; public ClusterGrpcService() { this.channelManager = new ChannelManager(); + this.pollCommandResponseManager = new PollCommandResponseManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.receiveMessageService = new ReceiveMessageService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); - this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager); + this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 2f5a1c86b5..9c6522aa41 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -66,6 +66,9 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; @@ -86,9 +89,13 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHand import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseFuture; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.remoting.RemotingServer; +import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; @@ -101,6 +108,7 @@ public class LocalGrpcService implements GrpcForwardService { private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; + private final PollCommandResponseManager pollCommandResponseManager; private final RouteService routeService; public LocalGrpcService(BrokerController brokerController) { @@ -108,6 +116,7 @@ public class LocalGrpcService implements GrpcForwardService { this.channelManager = new ChannelManager(); // TransactionStateChecker is not used in Local mode. ConnectorManager connectorManager = new ConnectorManager(null); + this.pollCommandResponseManager = new PollCommandResponseManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); } @@ -139,7 +148,7 @@ public class LocalGrpcService implements GrpcForwardService { } } - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, request.getClientId()); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, request.getClientId(), pollCommandResponseManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -381,16 +390,48 @@ public class LocalGrpcService implements GrpcForwardService { return future; } - @Override public CompletableFuture reportThreadStackTrace(Context ctx, + @Override + public CompletableFuture reportThreadStackTrace(Context ctx, ReportThreadStackTraceRequest request) { String commandId = request.getCommandId(); - return null; + String threadStack = request.getThreadStackTrace(); + PollCommandResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); + if (pollCommandResponseFuture != null) { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); + remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(threadStack); + remotingCommand.setBody(runningInfo.encode()); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + } + } + return CompletableFuture.completedFuture(ReportThreadStackTraceResponse.newBuilder() + .setCommon(ResponseBuilder.buildSuccessCommon()) + .build()); } @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { - return null; + String commandId = request.getCommandId(); + PollCommandResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); + if (pollCommandResponseFuture != null) { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); + remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); + ConsumeMessageDirectlyResult result = Converter.buildConsumeMessageDirectlyResult(request); + remotingCommand.setBody(result.encode()); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + } + } + return CompletableFuture.completedFuture(ReportMessageConsumptionResultResponse.newBuilder() + .setCommon(ResponseBuilder.buildSuccessCommon()) + .build()); } @Override public CompletableFuture notifyClientTermination(Context ctx, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index 95fa09acf3..02c2003fb2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -33,6 +33,7 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,11 +50,13 @@ public class ClientService extends BaseService { private final ConsumerManager consumerManager = new ConsumerManager((event, group, args) -> { }); private final ProducerManager producerManager; + private final PollCommandResponseManager pollCommandResponseManager; - public ClientService(ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager) { + public ClientService(ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager, PollCommandResponseManager pollCommandResponseManager) { super(connectorManager); scheduledExecutorService.scheduleWithFixedDelay(this::scanNotActiveChannel, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); this.channelManager = channelManager; + this.pollCommandResponseManager = pollCommandResponseManager; this.producerManager = new ProducerManager(); this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); @@ -66,7 +69,7 @@ public class ClientService extends BaseService { if (request.hasProducerData()) { String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); producerManager.registerProducer(producerGroup, clientChannelInfo); } @@ -74,7 +77,7 @@ public class ClientService extends BaseService { if (request.hasConsumerData()) { ConsumerData consumerData = request.getConsumerData(); String consumerGroup = Converter.getResourceNameWithNamespace(consumerData.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, consumerGroup, clientId); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, consumerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); consumerManager.registerConsumer( From 153b2ddd413b962f0d03cd21fa7290c5ee00b240 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 17 Mar 2022 17:29:03 +0800 Subject: [PATCH 049/338] [ISSUE #3949] Implement notifyClientTermination and changeInvisibleDuration --- .../rocketmq/proxy/grpc/common/Converter.java | 13 +++++ .../proxy/grpc/service/LocalGrpcService.java | 52 +++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 4c276ee6cc..69b0a27f4d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -34,6 +34,7 @@ import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessageType; import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NotifyClientTerminationRequest; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.ProducerData; import apache.rocketmq.v1.PullMessageRequest; @@ -79,6 +80,7 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; @@ -661,4 +663,15 @@ public class Converter { return consumeMessageDirectlyResult; } + public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(NotifyClientTerminationRequest request) { + UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); + header.setClientID(request.getClientId()); + if (request.hasProducerGroup()) { + header.setProducerGroup(getResourceNameWithNamespace(request.getProducerGroup())); + } + if (request.hasConsumerGroup()) { + header.setConsumerGroup(getResourceNameWithNamespace(request.getConsumerGroup())); + } + return header; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 9c6522aa41..63340febff 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -65,16 +65,19 @@ import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; @@ -283,7 +286,7 @@ public class LocalGrpcService implements GrpcForwardService { .build(); future.complete(response); } catch (Exception e) { - LOGGER.error("Exception raised while changeInvisibleTime", e); + LOGGER.error("Exception raised while nackMessage", e); future.completeExceptionally(e); } return future; @@ -436,12 +439,55 @@ public class LocalGrpcService implements GrpcForwardService { @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - return null; + Channel channel = channelManager.createChannel(); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + UnregisterClientRequestHeader header = Converter.buildUnregisterClientRequestHeader(request); + + RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); + remotingCommand.makeCustomHeaderToNet(); + try { + this.brokerController.getClientManageProcessor().unregisterClient(simpleChannelHandlerContext, remotingCommand); + } catch (Exception ignored) { + } + return new CompletableFuture<>(); } @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { - return null; + Channel channel = channelManager.createChannel(); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + + ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); + command.makeCustomHeaderToNet(); + + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() + .processRequest(channelHandlerContext, command); + ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); + ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + if (responseCommand.getCode() == ResponseCode.SUCCESS) { + builder.setReceiptHandle(ReceiptHandle.builder() + .startOffset(requestHeader.getOffset()) + .retrieveTime(responseHeader.getPopTime()) + .invisibleTime(responseHeader.getInvisibleTime()) + .reviveQueueId(responseHeader.getReviveQid()) + .topic(Converter.getResourceNameWithNamespace(request.getTopic())) + .brokerName(brokerController.getBrokerConfig().getBrokerName()) + .queueId(requestHeader.getQueueId()) + .offset(requestHeader.getOffset()) + .build() + .encode()); + } + + future.complete(builder.build()); + } catch (Exception e) { + LOGGER.error("Exception raised while changeInvisibleDuration", e); + future.completeExceptionally(e); + } + return future; } @Override public void start() throws Exception { From 527a38cefe57788968b647bd11b6e726116fdee8 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 17 Mar 2022 19:13:23 +0800 Subject: [PATCH 050/338] [ISSUE #3949] Implement pull and stream --- .../adapter/channel/PullMessageChannel.java | 29 ++++++++++ .../handler/PullMessageResponseHandler.java | 56 ++++++++++++++++++ .../proxy/grpc/service/LocalGrpcService.java | 57 ++++++++++++++++++- 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java new file mode 100644 index 0000000000..533bea1810 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.channel; + +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import org.apache.rocketmq.proxy.channel.InvocationChannel; +import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; + +public class PullMessageChannel extends InvocationChannel { + public PullMessageChannel(PullMessageResponseHandler handler) { + super(handler); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java new file mode 100644 index 0000000000..ce85e2e4fe --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.adapter.handler; + +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import java.nio.ByteBuffer; +import java.util.List; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; +import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class PullMessageResponseHandler implements ResponseHandler { + @Override public void handle(RemotingCommand responseCommand, + InvocationContext context) { + try { + PullMessageResponseHeader responseHeader = (PullMessageResponseHeader) responseCommand.readCustomHeader(); + PullMessageResponse.Builder builder = PullMessageResponse.newBuilder(); + if (responseCommand.getCode() == ResponseCode.SUCCESS) { + ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); + List msgFoundList = MessageDecoder.decodes(byteBuffer); + for (MessageExt messageExt : msgFoundList) { + builder.addMessages(Converter.buildMessage(messageExt)); + } + } + PullMessageResponse response = builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())) + .setMinOffset(responseHeader.getMinOffset()) + .setNextOffset(responseHeader.getNextBeginOffset()) + .setMaxOffset(responseHeader.getMaxOffset()) + .build(); + context.getResponse().complete(response); + } catch (Exception e) { + context.getResponse().completeExceptionally(e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 63340febff..a13e7c517c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -35,12 +35,14 @@ import apache.rocketmq.v1.NackMessageResponse; import apache.rocketmq.v1.NoopCommand; import apache.rocketmq.v1.NotifyClientTerminationRequest; import apache.rocketmq.v1.NotifyClientTerminationResponse; +import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.PollCommandRequest; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.PullMessageRequest; import apache.rocketmq.v1.PullMessageResponse; import apache.rocketmq.v1.QueryAssignmentRequest; import apache.rocketmq.v1.QueryAssignmentResponse; +import apache.rocketmq.v1.QueryOffsetPolicy; import apache.rocketmq.v1.QueryOffsetRequest; import apache.rocketmq.v1.QueryOffsetResponse; import apache.rocketmq.v1.QueryRouteRequest; @@ -54,6 +56,7 @@ import apache.rocketmq.v1.ReportThreadStackTraceResponse; import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; +import com.google.protobuf.util.Timestamps; import com.google.rpc.Code; import io.grpc.Context; import io.netty.channel.Channel; @@ -76,6 +79,7 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHea import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; @@ -88,6 +92,8 @@ import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; +import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; @@ -352,11 +358,58 @@ public class LocalGrpcService implements GrpcForwardService { } @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return null; + Partition partition = request.getPartition(); + String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); + int queueId = partition.getId(); + + long offset; + if (request.getPolicy() == QueryOffsetPolicy.BEGINNING) { + offset = 0L; + } else if (request.getPolicy() == QueryOffsetPolicy.END) { + offset = brokerController.getMessageStore() + .getMaxOffsetInQueue(topicName, queueId); + } else { + long timestamp = Timestamps.toMillis(request.getTimePoint()); + offset = brokerController.getMessageStore() + .getOffsetInQueueByTime(topicName, queueId, timestamp); + } + return CompletableFuture.completedFuture(QueryOffsetResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) + .setOffset(offset) + .build()); } @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return null; + long timeRemaining = Context.current() + .getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + PullMessageRequestHeader requestHeader = Converter.buildPullMessageRequestHeader(request, pollTime); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); + command.makeCustomHeaderToNet(); + + PullMessageResponseHandler handler = new PullMessageResponseHandler(); + PullMessageChannel channel = channelManager.createChannel(() -> new PullMessageChannel(handler), PullMessageChannel.class); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); + CompletableFuture future = new CompletableFuture<>(); + InvocationContext context = new InvocationContext<>(request, future); + channel.registerInvocationContext(command.getOpaque(), context); + try { + RemotingCommand response = brokerController.getPullMessageProcessor() + .processRequest(channelHandlerContext, command); + if (response != null) { + handler.handle(response, context); + channel.eraseInvocationContext(command.getOpaque()); + } + } catch (Exception e) { + LOGGER.error("Failed to process pull message command", e); + channel.eraseInvocationContext(command.getOpaque()); + future.completeExceptionally(e); + } + return future; } @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { From 83e9d838de28aedaa11ca8df10570a646b879e2d Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Thu, 17 Mar 2022 21:51:38 +0800 Subject: [PATCH 051/338] [ISSUE #3949] Do some refactoring for passing check style. --- .../grpc/service/cluster/ProducerService.java | 12 +++++++++--- .../grpc/service/cluster/PullMessageService.java | 16 +++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 1ee3d36c9d..a640f1df6e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -150,9 +150,15 @@ public class ProducerService extends BaseService { ConsumerSendMsgBackRequestHeader requestHeader = this.convertToConsumerSendMsgBackRequestHeader(ctx, request); CompletableFuture resultFuture = this.connectorManager.getForwardProducer() .sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - resultFuture.thenAccept(result -> future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) - .build())).exceptionally(throwable -> { + resultFuture + .thenAccept(result -> + future.complete( + ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) + .build() + ) + ) + .exceptionally(throwable -> { future.completeExceptionally(throwable); return null; }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 587059b38b..559ae458a0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -83,13 +83,15 @@ public class PullMessageService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, brokerName); offsetFuture = this.defaultForwardClient.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } - offsetFuture.thenAccept(result -> future.complete(QueryOffsetResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setOffset(result) - .build())).exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + offsetFuture.thenAccept(result -> future.complete( + QueryOffsetResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setOffset(result) + .build())) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } From afc2aeab63b3cf13ed7c781c1e46f76288284f4b Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 18 Mar 2022 14:39:55 +0800 Subject: [PATCH 052/338] [ISSUE #3949] Do some refactoring for readability. --- .../proxy/grpc/common/ParameterConverter.java | 1 + .../grpc/service/ClusterGrpcService.java | 6 +-- ...ctor.java => AssignmentQueueSelector.java} | 2 +- ...ssageService.java => ConsumerService.java} | 16 +++---- ...va => DefaultAssignmentQueueSelector.java} | 4 +- ...tor.java => DefaultReadQueueSelector.java} | 4 +- ...or.java => DefaultWriteQueueSelector.java} | 6 +-- .../grpc/service/cluster/ProducerService.java | 33 +++++++------ .../service/cluster/PullMessageService.java | 47 +++++++++---------- ...ueSelector.java => ReadQueueSelector.java} | 2 +- .../grpc/service/cluster/RouteService.java | 26 +++++----- ...eSelector.java => WriteQueueSelector.java} | 2 +- .../DefaultProducerQueueSelectorTest.java | 8 ++-- .../service/cluster/ProducerServiceTest.java | 8 ++-- 14 files changed, 82 insertions(+), 83 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{RouteAssignmentQueueSelector.java => AssignmentQueueSelector.java} (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ReceiveMessageService.java => ConsumerService.java} (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{DefaultRouteAssignmentQueueSelector.java => DefaultAssignmentQueueSelector.java} (90%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{DefaultReceiveMessageQueueSelector.java => DefaultReadQueueSelector.java} (92%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{DefaultProducerQueueSelector.java => DefaultWriteQueueSelector.java} (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ReceiveMessageQueueSelector.java => ReadQueueSelector.java} (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ProducerQueueSelector.java => WriteQueueSelector.java} (96%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java index 6e9ce1643c..7561a21bc4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.grpc.common; import io.grpc.Context; +@FunctionalInterface public interface ParameterConverter { R convert(Context ctx, T parameter) throws Throwable; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 304e4598e2..4366b80c0b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -70,7 +70,7 @@ import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ReceiveMessageService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; import org.slf4j.Logger; @@ -85,7 +85,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ChannelManager channelManager; private final ConnectorManager connectorManager; private final ProducerService producerService; - private final ReceiveMessageService receiveMessageService; + private final ConsumerService receiveMessageService; private final RouteService routeService; private final ClientService clientService; private final PullMessageService pullMessageService; @@ -96,7 +96,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.channelManager = new ChannelManager(); this.pollCommandResponseManager = new PollCommandResponseManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); - this.receiveMessageService = new ReceiveMessageService(connectorManager); + this.receiveMessageService = new ConsumerService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java index ecdfd63539..fb2422736d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java @@ -21,7 +21,7 @@ import io.grpc.Context; import java.util.List; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -public interface RouteAssignmentQueueSelector { +public interface AssignmentQueueSelector { List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index ffd91a14c3..505fb46e18 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -49,22 +49,22 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -public class ReceiveMessageService extends BaseService { +public class ConsumerService extends BaseService { private final ForwardReadConsumer readConsumer; private final ForwardWriteConsumer writeConsumer; - private volatile ReceiveMessageQueueSelector receiveMessageQueueSelector; + private volatile ReadQueueSelector readQueueSelector; private volatile ResponseHook receiveMessageHook = null; private volatile ResponseHook ackMessageHook = null; private volatile ResponseHook nackMessageHook = null; - public ReceiveMessageService(ConnectorManager connectorManager) { + public ConsumerService(ConnectorManager connectorManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); - this.receiveMessageQueueSelector = new DefaultReceiveMessageQueueSelector(connectorManager.getTopicRouteCache()); + this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { @@ -76,7 +76,7 @@ public class ReceiveMessageService extends BaseService { }); try { PopMessageRequestHeader requestHeader = this.convertToPopMessageRequestHeader(ctx, request); - SelectableMessageQueue messageQueue = this.receiveMessageQueueSelector.select(ctx, request, requestHeader); + SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); CompletableFuture popResultFuture = this.readConsumer.popMessage( messageQueue.getBrokerAddr(), @@ -228,9 +228,9 @@ public class ReceiveMessageService extends BaseService { .build(); } - public void setReceiveMessageQueueSelector( - ReceiveMessageQueueSelector receiveMessageQueueSelector) { - this.receiveMessageQueueSelector = receiveMessageQueueSelector; + public void setReadQueueSelector( + ReadQueueSelector readQueueSelector) { + this.readQueueSelector = readQueueSelector; } public void setReceiveMessageHook( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java similarity index 90% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java index e112853b54..1738cb1f3e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultRouteAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java @@ -24,11 +24,11 @@ import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.common.Converter; -public class DefaultRouteAssignmentQueueSelector implements RouteAssignmentQueueSelector { +public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { private final TopicRouteCache topicRouteCache; - public DefaultRouteAssignmentQueueSelector(TopicRouteCache topicRouteCache) { + public DefaultAssignmentQueueSelector(TopicRouteCache topicRouteCache) { this.topicRouteCache = topicRouteCache; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java similarity index 92% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java index df59b5e12b..284270921c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReceiveMessageQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java @@ -23,11 +23,11 @@ import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -public class DefaultReceiveMessageQueueSelector implements ReceiveMessageQueueSelector { +public class DefaultReadQueueSelector implements ReadQueueSelector { private final TopicRouteCache topicRouteCache; - public DefaultReceiveMessageQueueSelector(TopicRouteCache topicRouteCache) { + public DefaultReadQueueSelector(TopicRouteCache topicRouteCache) { this.topicRouteCache = topicRouteCache; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java index 5b7122f1c8..1cc9ba7bc6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java @@ -26,12 +26,12 @@ import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class DefaultProducerQueueSelector implements ProducerQueueSelector { +public class DefaultWriteQueueSelector implements WriteQueueSelector { - private static final Logger log = LoggerFactory.getLogger(DefaultProducerQueueSelector.class); + private static final Logger log = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); protected final TopicRouteCache topicRouteCache; - public DefaultProducerQueueSelector(TopicRouteCache topicRouteCache) { + public DefaultWriteQueueSelector(TopicRouteCache topicRouteCache) { this.topicRouteCache = topicRouteCache; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index a640f1df6e..0435c8f794 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -23,6 +23,7 @@ import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; +import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; @@ -39,25 +40,23 @@ import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import java.util.concurrent.CompletableFuture; - public class ProducerService extends BaseService { - private volatile ProducerQueueSelector messageQueueSelector; + private volatile WriteQueueSelector writeQueueSelector; private volatile ResponseHook sendMessageHook = null; private volatile ResponseHook forwardMessageToDLQHook = null; public ProducerService(ConnectorManager connectorManager) { super(connectorManager); - messageQueueSelector = new DefaultProducerQueueSelector(this.connectorManager.getTopicRouteCache()); + writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); } public void setSendMessageHook(ResponseHook sendMessageHook) { this.sendMessageHook = sendMessageHook; } - public void setMessageQueueSelector(ProducerQueueSelector messageQueueSelector) { - this.messageQueueSelector = messageQueueSelector; + public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { + this.writeQueueSelector = writeQueueSelector; } public void setForwardMessageToDLQHook( @@ -77,7 +76,7 @@ public class ProducerService extends BaseService { Pair requestPair = this.convertSendMessageRequest(ctx, request); SendMessageRequestHeader requestHeader = requestPair.getLeft(); org.apache.rocketmq.common.message.Message message = requestPair.getRight(); - SelectableMessageQueue addressableMessageQueue = messageQueueSelector.selectQueue(ctx, request, requestHeader, message); + SelectableMessageQueue addressableMessageQueue = writeQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); if (addressableMessageQueue == null) { @@ -151,17 +150,17 @@ public class ProducerService extends BaseService { CompletableFuture resultFuture = this.connectorManager.getForwardProducer() .sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); resultFuture - .thenAccept(result -> - future.complete( - ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) - .build() - ) + .thenAccept(result -> + future.complete( + ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) + .build() ) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + ) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 559ae458a0..9c78a2ebb2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -26,6 +26,10 @@ import apache.rocketmq.v1.QueryOffsetResponse; import com.google.protobuf.util.Timestamps; import com.google.rpc.Code; import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.message.MessageExt; @@ -41,11 +45,6 @@ import org.apache.rocketmq.proxy.grpc.common.ProxyException; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - public class PullMessageService extends BaseService { private final DefaultForwardClient defaultForwardClient; @@ -84,14 +83,14 @@ public class PullMessageService extends BaseService { offsetFuture = this.defaultForwardClient.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } offsetFuture.thenAccept(result -> future.complete( - QueryOffsetResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setOffset(result) - .build())) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + QueryOffsetResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setOffset(result) + .build())) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } @@ -113,19 +112,19 @@ public class PullMessageService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, brokerName); CompletableFuture pullResultFuture = this.connectorManager.getForwardReadConsumer() - .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); pullResultFuture - .thenAccept(pullResult -> { - try { - future.complete(convertToPullMessageResponse(ctx, request, pullResult)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { + .thenAccept(pullResult -> { + try { + future.complete(convertToPullMessageResponse(ctx, request, pullResult)); + } catch (Throwable throwable) { future.completeExceptionally(throwable); - return null; - }); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java index c671709cff..cd0702d1c1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReceiveMessageQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java @@ -21,7 +21,7 @@ import io.grpc.Context; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -public interface ReceiveMessageQueueSelector { +public interface ReadQueueSelector { SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index c551135e9d..e7c64036b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -58,7 +58,7 @@ public class RouteService extends BaseService { private volatile ResponseHook queryRouteHook = null; private volatile ParameterConverter queryAssignmentEndpointConverter; - private volatile RouteAssignmentQueueSelector assignmentQueueSelector; + private volatile AssignmentQueueSelector assignmentQueueSelector; private volatile ResponseHook queryAssignmentHook = null; public RouteService(ProxyMode mode, ConnectorManager connectorManager) { @@ -67,7 +67,7 @@ public class RouteService extends BaseService { this.mode = mode; queryRouteEndpointConverter = (ctx, parameter) -> parameter; queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; - assignmentQueueSelector = new DefaultRouteAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); + assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); } public void setQueryRouteEndpointConverter(ParameterConverter queryRouteEndpointConverter) { @@ -83,7 +83,7 @@ public class RouteService extends BaseService { this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; } - public void setAssignmentQueueSelector(RouteAssignmentQueueSelector assignmentQueueSelector) { + public void setAssignmentQueueSelector(AssignmentQueueSelector assignmentQueueSelector) { this.assignmentQueueSelector = assignmentQueueSelector; } @@ -179,25 +179,25 @@ public class RouteService extends BaseService { int queueIdIndex = 0; for (int i = 0; i < r; i++) { Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ) - .build(); + .setId(queueIdIndex++) + .setPermission(Permission.READ) + .build(); partitionList.add(partition); } for (int i = 0; i < w; i++) { Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.WRITE) - .build(); + .setId(queueIdIndex++) + .setPermission(Permission.WRITE) + .build(); partitionList.add(partition); } for (int i = 0; i < rw; i++) { Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ_WRITE) - .build(); + .setId(queueIdIndex++) + .setPermission(Permission.READ_WRITE) + .build(); partitionList.add(partition); } @@ -278,7 +278,7 @@ public class RouteService extends BaseService { return future; } - private Map> buildBrokerMap(List brokerDataList) { + private Map> buildBrokerMap(List brokerDataList) { Map> brokerMap = new HashMap<>(); for (BrokerData brokerData : brokerDataList) { Map brokerIdMap = new HashMap<>(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java index ae4619db88..8605d11062 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java @@ -21,7 +21,7 @@ import io.grpc.Context; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -public interface ProducerQueueSelector { +public interface WriteQueueSelector { SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, org.apache.rocketmq.common.message.Message message); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java index 35495513fe..21accfcf1e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java @@ -59,7 +59,7 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); - ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); @@ -83,7 +83,7 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); - ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); @@ -106,7 +106,7 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); - ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); @@ -134,7 +134,7 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build()) .build()) .build(); - ProducerQueueSelector queueSelector = new DefaultProducerQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 3d00c3dbbd..708d683d76 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -72,7 +72,7 @@ public class ProducerServiceTest extends BaseServiceTest { 1L, "txId", "offsetMsgId", "regionId")); ProducerService producerService = new ProducerService(this.clientManager); - producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> + producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); @@ -90,7 +90,7 @@ public class ProducerServiceTest extends BaseServiceTest { public void testSendMessageNoQueueSelect() { ProducerService producerService = new ProducerService(this.clientManager); - producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> null); + producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> null); CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() .setMessage(Message.newBuilder() @@ -126,7 +126,7 @@ public class ProducerServiceTest extends BaseServiceTest { sendResultFuture.completeExceptionally(ex); ProducerService producerService = new ProducerService(this.clientManager); - producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> + producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); @@ -146,7 +146,7 @@ public class ProducerServiceTest extends BaseServiceTest { RuntimeException ex = new RuntimeException(); ProducerService producerService = new ProducerService(this.clientManager); - producerService.setMessageQueueSelector((ctx, request, requestHeader, message) -> { + producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> { throw ex; }); producerService.setSendMessageHook((request, response, t) -> { From 5c8374c4315e9aada369d163eadc1f790f6b1304 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 18 Mar 2022 14:15:08 +0800 Subject: [PATCH 053/338] [ISSUE #3949] Add unit test --- .../grpc/service/LocalGrpcServiceTest.java | 422 ++++++++++++++++-- 1 file changed, 390 insertions(+), 32 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 3d831a751a..093b0a47a6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -17,14 +17,35 @@ package org.apache.rocketmq.proxy.grpc.service; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationResponse; +import apache.rocketmq.v1.ConsumerData; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v1.HeartbeatRequest; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.ProducerData; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryOffsetPolicy; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.Resource; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.rpc.Code; import io.grpc.Context; @@ -33,22 +54,34 @@ import io.netty.channel.ChannelHandlerContext; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.AckMessageProcessor; +import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; import org.apache.rocketmq.broker.processor.ClientManageProcessor; +import org.apache.rocketmq.broker.processor.EndTransactionProcessor; import org.apache.rocketmq.broker.processor.PopMessageProcessor; +import org.apache.rocketmq.broker.processor.PullMessageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.common.BrokerConfig; import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.apache.rocketmq.store.MessageStore; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -57,6 +90,7 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; @RunWith(MockitoJUnitRunner.class) public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @@ -66,6 +100,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Mock private PopMessageProcessor popMessageProcessorMock; @Mock + private PullMessageProcessor pullMessageProcessorMock; + @Mock private BrokerController brokerControllerMock; private Metadata metadata; @@ -75,6 +111,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { super.before(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); + Mockito.when(brokerControllerMock.getPullMessageProcessor()).thenReturn(pullMessageProcessorMock); + Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); localGrpcService = new LocalGrpcService(brokerControllerMock); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); @@ -83,25 +121,51 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { } @Test - public void testHeartbeat() { + public void testHeartbeatProducerData() throws Exception { RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(response); Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); - HeartbeatRequest request = HeartbeatRequest.newBuilder().getDefaultInstanceForType(); + HeartbeatRequest request = HeartbeatRequest.newBuilder() + .setClientId("test-client") + .setProducerData(ProducerData.newBuilder() + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .build()) + .build(); CompletableFuture grpcFuture = localGrpcService.heartbeat( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); - grpcFuture.thenAccept(r -> { - assertThat(r.getCommon().getStatus().getCode()) - .isEqualTo(Code.OK.getNumber()); - assertThat(r.getCommon().getStatus().getMessage()) - .isEqualTo(null); - }); + HeartbeatResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()) + .isEqualTo(Code.OK.getNumber()); } @Test - public void testSendMessageError() throws RemotingCommandException { + public void testHeartbeatConsumerData() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); + Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); + HeartbeatRequest request = HeartbeatRequest.newBuilder() + .setClientId("test-client") + .setConsumerData(ConsumerData.newBuilder() + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .build()) + .build(); + CompletableFuture grpcFuture = localGrpcService.heartbeat( + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + HeartbeatResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()) + .isEqualTo(Code.OK.getNumber()); + } + + @Test + public void testSendMessageError() throws Exception { String remark = "store putMessage return null"; RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SYSTEM_ERROR, remark); CompletableFuture future = CompletableFuture.completedFuture(response); @@ -117,16 +181,13 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); - grpcFuture.thenAccept(r -> { - assertThat(r.getCommon().getStatus().getCode()) - .isEqualTo(Code.INTERNAL.getNumber()); - assertThat(r.getCommon().getStatus().getMessage()) - .isEqualTo(remark); - }); + SendMessageResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()) + .isEqualTo(Code.INTERNAL.getNumber()); } @Test - public void testSendMessageWriteAndFlush() throws RemotingCommandException { + public void testSendMessageWriteAndFlush() throws Exception { CompletableFuture future = CompletableFuture.completedFuture(null); Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(future); @@ -140,11 +201,11 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); - grpcFuture.thenAccept(r -> assertThat(r).isNull()); + assertThat(grpcFuture.isDone()).isFalse(); } @Test - public void testSendMessageWithException() throws RemotingCommandException { + public void testSendMessageWithException() throws Exception { Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenThrow(new RemotingCommandException("test")); SendMessageRequest request = SendMessageRequest.newBuilder() @@ -157,10 +218,13 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); - grpcFuture.thenAccept(r -> assertThat(r).isNull()).exceptionally(e -> { - assertThat(e).isInstanceOf(RemotingCommandException.class); - return null; - }); + assertThatThrownBy(() -> { + try { + grpcFuture.get(); + } catch (ExecutionException e) { + throw e.getCause(); + } + }).isInstanceOf(RemotingCommandException.class); } @Test @@ -177,25 +241,30 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { messageExt.putUserProperty("key", "value"); PopMessageResponseHeader responseHeader = new PopMessageResponseHeader(); responseHeader.setInvisibleTime(invisibleTime); - RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(ResponseCode.SUCCESS, responseHeader); + RemotingCommand remotingCommand = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); remotingCommand.setBody(MessageDecoder.encode(messageExt, true)); remotingCommand.makeCustomHeaderToNet(); Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(remotingCommand); - ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder().getDefaultInstanceForType(); + ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .build()) + .build(); CompletableFuture grpcFuture = localGrpcService.receiveMessage( Context.current() .withValue(InterceptorConstants.METADATA, metadata) .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))) .attach(), request); - grpcFuture.thenAccept(r -> { - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); - assertThat(r.getMessagesCount()).isEqualTo(0); - assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); - assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); - assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); - }); + ReceiveMessageResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getMessagesCount()).isEqualTo(1); + assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); + assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); + assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); } @Test @@ -209,6 +278,295 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))) .attach(), request); - grpcFuture.thenAccept(r -> assertThat(r).isNull()); + assertThat(grpcFuture.isDone()).isFalse(); + } + + @Test + public void testAckMessage() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + AckMessageProcessor ackMessageProcessorMock = Mockito.mock(AckMessageProcessor.class); + Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); + Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + AckMessageRequest request = AckMessageRequest.newBuilder().setReceiptHandle( + ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topic("topic") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode() + ).build(); + CompletableFuture grpcFuture = localGrpcService.ackMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + AckMessageResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + + @Test + public void testNackMessage() throws Exception { + ChangeInvisibleTimeResponseHeader responseHeader = new ChangeInvisibleTimeResponseHeader(); + responseHeader.setInvisibleTime(1000L); + responseHeader.setPopTime(0L); + responseHeader.setReviveQid(0); + RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); + + ChangeInvisibleTimeProcessor changeInvisibleTimeProcessor = Mockito.mock(ChangeInvisibleTimeProcessor.class); + Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessor); + Mockito.when(changeInvisibleTimeProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + NackMessageRequest request = NackMessageRequest.newBuilder().setReceiptHandle( + ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topic("topic") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode() + ).build(); + CompletableFuture grpcFuture = localGrpcService.nackMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + NackMessageResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + + @Test + public void testForwardMessageToDeadLetterQueue() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + CompletableFuture future = CompletableFuture.completedFuture(response); + Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), + Mockito.argThat(argument -> argument.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK))) + .thenReturn(future); + ForwardMessageToDeadLetterQueueRequest request = ForwardMessageToDeadLetterQueueRequest.newBuilder() + .setReceiptHandle(ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topic("topic") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()) + .build(); + CompletableFuture grpcFuture = localGrpcService.forwardMessageToDeadLetterQueue( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + ForwardMessageToDeadLetterQueueResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + + @Test + public void testEndTransaction() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + + EndTransactionProcessor endTransactionProcessor = Mockito.mock(EndTransactionProcessor.class); + Mockito.when(brokerControllerMock.getEndTransactionProcessor()).thenReturn(endTransactionProcessor); + Mockito.when(endTransactionProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), + Mockito.any(RemotingCommand.class))) + .thenReturn(response); + EndTransactionRequest request = EndTransactionRequest.newBuilder() + .setMessageId("123") + .setTransactionId(TransactionId.genFromBrokerTransactionId( + new InetSocketAddress("0.0.0.0", 80), "123", 123, 123 + ).getProxyTransactionId() + ) + .build(); + CompletableFuture grpcFuture = localGrpcService.endTransaction( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + EndTransactionResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + + @Test + public void testQueryOffset() throws Exception { + String topic = "test-topic"; + int queueId = 1; + + long maxOffset = 10L; + long timeOffset = 5L; + MessageStore messageStore = Mockito.mock(MessageStore.class); + Mockito.when(brokerControllerMock.getMessageStore()).thenReturn(messageStore); + Mockito.when(messageStore.getMaxOffsetInQueue(Mockito.eq(topic), Mockito.eq(queueId))).thenReturn(maxOffset); + Mockito.when(messageStore.getOffsetInQueueByTime(Mockito.eq(topic), Mockito.eq(queueId), Mockito.anyLong())).thenReturn(timeOffset); + + QueryOffsetRequest request = QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setId(queueId) + .build()) + .setPolicy(QueryOffsetPolicy.BEGINNING) + .build(); + CompletableFuture grpcFuture = localGrpcService.queryOffset( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + QueryOffsetResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getOffset()).isEqualTo(0); + + request = QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setId(queueId) + .build()) + .setPolicy(QueryOffsetPolicy.END) + .build(); + grpcFuture = localGrpcService.queryOffset( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getOffset()).isEqualTo(maxOffset); + + request = QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setId(queueId) + .build()) + .setTimePoint(Timestamp.newBuilder() + .setSeconds(1000L) + .build()) + .setPolicy(QueryOffsetPolicy.TIME_POINT) + .build(); + grpcFuture = localGrpcService.queryOffset( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getOffset()).isEqualTo(timeOffset); + } + + @Test + public void testReportThreadStackTrace() throws Exception { + + } + + @Test + public void testNotifyClientTermination() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + + ClientManageProcessor clientManageProcessor = Mockito.mock(ClientManageProcessor.class); + Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessor); + Mockito.when(clientManageProcessor.unregisterClient(Mockito.any(ChannelHandlerContext.class), + Mockito.any(RemotingCommand.class))) + .thenReturn(response); + NotifyClientTerminationRequest request = NotifyClientTerminationRequest.newBuilder() + .setProducerGroup(Resource.newBuilder() + .setName("group") + .build()) + .build(); + localGrpcService.notifyClientTermination( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + Mockito.verify(clientManageProcessor, Mockito.times(1)) + .unregisterClient(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); + } + + @Test + public void testChangeInvisibleDuration() throws Exception { + long invisibleTime = 1000L; + int queueId = 1; + long offset = 123L; + ChangeInvisibleTimeResponseHeader responseHeader = new ChangeInvisibleTimeResponseHeader(); + responseHeader.setInvisibleTime(1000L); + responseHeader.setPopTime(0L); + responseHeader.setReviveQid(0); + RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); + + ChangeInvisibleTimeProcessor changeInvisibleTimeProcessor = Mockito.mock(ChangeInvisibleTimeProcessor.class); + Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessor); + Mockito.when(changeInvisibleTimeProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + ChangeInvisibleDurationRequest request = ChangeInvisibleDurationRequest.newBuilder().setReceiptHandle( + ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(invisibleTime) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topic("topic") + .brokerName("brokerName") + .queueId(queueId) + .offset(offset) + .build().encode() + ).build(); + CompletableFuture grpcFuture = localGrpcService.changeInvisibleDuration( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + ChangeInvisibleDurationResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + ReceiptHandle handle = ReceiptHandle.decode(r.getReceiptHandle()); + assertThat(handle.getInvisibleTime()).isEqualTo(invisibleTime); + assertThat(handle.getQueueId()).isEqualTo(queueId); + assertThat(handle.getOffset()).isEqualTo(offset); + } + + @Test + public void testPullMessageSuccess() throws Exception { + String topic = "topic"; + byte[] body = "123".getBytes(StandardCharsets.UTF_8); + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody(body); + messageExt.putUserProperty("key", "value"); + + long minOffset = 1L; + long nextOffset = 3L; + long maxOffset = 10L; + PullMessageResponseHeader responseHeader = new PullMessageResponseHeader(); + responseHeader.setMinOffset(minOffset); + responseHeader.setNextBeginOffset(nextOffset); + responseHeader.setMaxOffset(maxOffset); + RemotingCommand remotingCommand = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); + remotingCommand.setBody(MessageDecoder.encode(messageExt, true)); + remotingCommand.makeCustomHeaderToNet(); + Mockito.when(pullMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(remotingCommand); + PullMessageRequest request = PullMessageRequest.newBuilder().getDefaultInstanceForType(); + CompletableFuture grpcFuture = localGrpcService.pullMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("test"))) + .attach(), request); + PullMessageResponse r = grpcFuture.get(); + assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getMessagesCount()).isEqualTo(1); + assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); + assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); + assertThat(r.getMinOffset()).isEqualTo(minOffset); + assertThat(r.getNextOffset()).isEqualTo(nextOffset); + assertThat(r.getMaxOffset()).isEqualTo(maxOffset); } } \ No newline at end of file From 053c6437fbc4e6646a5507f14cd57ae831ebbdae Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 18 Mar 2022 14:15:34 +0800 Subject: [PATCH 054/338] [ISSUE #3949] Add DelayPolicy --- .../rocketmq/proxy/config/ProxyConfig.java | 19 +++++ .../rocketmq/proxy/grpc/common/Converter.java | 6 +- .../proxy/grpc/common/DelayPolicy.java | 82 +++++++++++++++++++ .../proxy/grpc/service/LocalGrpcService.java | 5 +- .../grpc/service/cluster/ConsumerService.java | 6 +- 5 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/DelayPolicy.java 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 9c40facf87..cb23d66c6b 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 @@ -79,6 +79,9 @@ public class ProxyConfig { private int longPollingReserveTimeInMillis = 10000; + private int retryDelayLevelDelta = 3; + private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; + public Integer getHealthCheckPort() { return healthCheckPort; } @@ -366,4 +369,20 @@ public class ProxyConfig { public void setLongPollingReserveTimeInMillis(int longPollingReserveTimeInMillis) { this.longPollingReserveTimeInMillis = longPollingReserveTimeInMillis; } + + public int getRetryDelayLevelDelta() { + return retryDelayLevelDelta; + } + + public void setRetryDelayLevelDelta(int retryDelayLevelDelta) { + this.retryDelayLevelDelta = retryDelayLevelDelta; + } + + public String getMessageDelayLevel() { + return messageDelayLevel; + } + + public void setMessageDelayLevel(String messageDelayLevel) { + this.messageDelayLevel = messageDelayLevel; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 69b0a27f4d..03f4877313 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -88,6 +88,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -179,7 +180,8 @@ public class Converter { return ackMessageRequestHeader; } - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request) { + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, + DelayPolicy delayPolicy) { String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); @@ -191,7 +193,7 @@ public class Converter { changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(0L); + changeInvisibleTimeRequestHeader.setInvisibleTime(delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); return changeInvisibleTimeRequestHeader; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/DelayPolicy.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/DelayPolicy.java new file mode 100644 index 0000000000..18d442e7a7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/DelayPolicy.java @@ -0,0 +1,82 @@ +/* + * 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.grpc.common; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DelayPolicy { + private List delayIntervalList; + + private DelayPolicy(List delayIntervalList) { + this.delayIntervalList = delayIntervalList; + } + + public long getDelayInterval(int index) { + int size = delayIntervalList.size(); + if (index >= size) { + throw new IllegalArgumentException("Out of index, size: " + size); + } + return delayIntervalList.get(index); + } + + public void refresh(String messageDelayLevel) { + delayIntervalList = buildList(messageDelayLevel); + } + + public static DelayPolicy build(String messageDelayLevel) { + return new DelayPolicy(buildList(messageDelayLevel)); + } + + private static List buildList(String messageDelayLevel) { + List delayLevelList = Lists.newArrayList(Splitter.on(" ").split(messageDelayLevel)); + List delayIntervalList = new ArrayList<>(); + for (String delayLevel : delayLevelList) { + final Pattern p = Pattern.compile("(\\d+)([smhd])"); + final Matcher m = p.matcher(delayLevel); + while (m.find()) + { + final int duration = Integer.parseInt(m.group(1)); + final String timeUnitString = m.group(2); + final long interval = toInterval(duration, timeUnitString); + delayIntervalList.add(interval); + } + } + return delayIntervalList; + } + + private static long toInterval(int duration, final String timeUnitString) { + switch (timeUnitString) { + case "s": + return TimeUnit.SECONDS.toMillis(duration); + case "m": + return TimeUnit.MINUTES.toMillis(duration); + case "h": + return TimeUnit.HOURS.toMillis(duration); + case "d": + return TimeUnit.DAYS.toMillis(duration); + default: + throw new IllegalArgumentException(String.format("%s is not a valid code [smhd]", timeUnitString)); + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index a13e7c517c..2072a21eae 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -97,6 +97,7 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseFuture; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; @@ -119,6 +120,7 @@ public class LocalGrpcService implements GrpcForwardService { private final ChannelManager channelManager; private final PollCommandResponseManager pollCommandResponseManager; private final RouteService routeService; + private final DelayPolicy delayPolicy; public LocalGrpcService(BrokerController brokerController) { this.brokerController = brokerController; @@ -127,6 +129,7 @@ public class LocalGrpcService implements GrpcForwardService { ConnectorManager connectorManager = new ConnectorManager(null); this.pollCommandResponseManager = new PollCommandResponseManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); + this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -279,7 +282,7 @@ public class LocalGrpcService implements GrpcForwardService { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request); + ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 505fb46e18..fb4d10bb7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -41,6 +41,7 @@ import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.common.ResponseHook; @@ -59,12 +60,15 @@ public class ConsumerService extends BaseService { private volatile ResponseHook ackMessageHook = null; private volatile ResponseHook nackMessageHook = null; + private final DelayPolicy delayPolicy; + public ConsumerService(ConnectorManager connectorManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); + this.delayPolicy = DelayPolicy.build(ConfigurationManager.getProxyConfig().getMessageDelayLevel()); } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { @@ -214,7 +218,7 @@ public class ConsumerService extends BaseService { } protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return Converter.buildChangeInvisibleTimeRequestHeader(request); + return Converter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { From a96b2144892f3b2e95524e6923e0a310d9ee86e3 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 18 Mar 2022 15:44:15 +0800 Subject: [PATCH 055/338] [ISSUE #3949] Improve readability. --- .../proxy/common/utils/FilterUtil.java | 19 +++++-- .../service/cluster/PullMessageService.java | 36 +++++-------- .../proxy/common/utils/FilterUtilTest.java | 51 +++++++++++++++++++ 3 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java index d5db649da0..a33c8c1762 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java @@ -17,15 +17,24 @@ package org.apache.rocketmq.proxy.common.utils; import java.util.Set; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; public class FilterUtil { - public static boolean isTagNotMatched(Set tagsSet, String tags) { + /** + * Whether the message's tag matches consumerGroup's SubscriptionData + * + * @param tagsSet, tagSet in {@link SubscriptionData}, tagSet empty means SubscriptionData.SUB_ALL(*) + * @param tags, message's tags, null means not tag attached to the message. + */ + public static boolean isTagMatched(Set tagsSet, String tags) { if (tagsSet.isEmpty()) { - return false; - } - if (tags == null) { return true; } - return !tagsSet.contains(tags); + + if (tags == null) { + return false; + } + + return tagsSet.contains(tags); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 9c78a2ebb2..f9f3a24986 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -26,13 +26,12 @@ import apache.rocketmq.v1.QueryOffsetResponse; import com.google.protobuf.util.Timestamps; import com.google.rpc.Code; import io.grpc.Context; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.utils.FilterUtil; @@ -145,32 +144,25 @@ public class PullMessageService extends BaseService { } protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { + PullMessageResponse.Builder responseBuilder = PullMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setMinOffset(result.getMinOffset()) + .setMaxOffset(result.getMaxOffset()) + .setNextOffset(result.getNextBeginOffset()); + SubscriptionData subscriptionData = Converter.buildSubscriptionData( Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); PullStatus status = result.getPullStatus(); if (status.equals(PullStatus.FOUND)) { - List messages = new ArrayList<>(); - for (MessageExt messageExt : result.getMsgFoundList()) { - if (FilterUtil.isTagNotMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { - continue; - } - messages.add(Converter.buildMessage(messageExt)); - } - return PullMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setMinOffset(result.getMinOffset()) - .setMaxOffset(result.getMaxOffset()) - .setNextOffset(result.getNextBeginOffset()) - .addAllMessages(messages) - .build(); + List messageList = result.getMsgFoundList().stream() + .filter(msg -> FilterUtil.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. + .map(Converter::buildMessage) + .collect(Collectors.toList()); + + return responseBuilder.addAllMessages(messageList).build(); } else { - return PullMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setMinOffset(result.getMinOffset()) - .setMaxOffset(result.getMaxOffset()) - .setNextOffset(result.getNextBeginOffset()) - .build(); + return responseBuilder.build(); } } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java new file mode 100644 index 0000000000..b6a5198a96 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java @@ -0,0 +1,51 @@ +/* + * 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.common.utils; + +import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FilterUtilTest { + @Test + public void testIsTagMatched() throws Exception { + SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); + assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); + } + + @Test + public void testIsTagNotMatched() throws Exception { + SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); + assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagB")).isFalse(); + } + + @Test + public void testIsTagMatchedStar() throws Exception { + SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "*"); + assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); + } + + @Test + public void testIsTagNotMatchedNull() throws Exception { + SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); + assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), null)).isFalse(); + } + +} From f9c3a5e49ba0a3b9e6483ce18b71252bb686416e Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 18 Mar 2022 16:12:08 +0800 Subject: [PATCH 056/338] [ISSUE #3949] Improve readability. --- .../rocketmq/proxy/channel/ChannelManager.java | 2 +- .../utils/{FilterUtil.java => FilterUtils.java} | 2 +- .../proxy/connector/DefaultForwardClient.java | 16 +++++++++++++--- .../rocketmq/proxy/grpc/common/Converter.java | 3 ++- .../grpc/interceptor/ContextInterceptor.java | 1 - .../grpc/interceptor/HeaderInterceptor.java | 1 - .../InterceptorConstants.java | 2 +- .../proxy/grpc/service/LocalGrpcService.java | 2 +- .../grpc/service/cluster/ClientService.java | 2 +- .../grpc/service/cluster/PullMessageService.java | 4 ++-- .../proxy/common/utils/FilterUtilTest.java | 8 ++++---- .../proxy/grpc/service/LocalGrpcServiceTest.java | 2 +- 12 files changed, 27 insertions(+), 18 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/{FilterUtil.java => FilterUtils.java} (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => interceptor}/InterceptorConstants.java (97%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 1d27b1633c..8fa53b3d7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -32,7 +32,7 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.common.Cleaner; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java index a33c8c1762..2c9b663a9a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtil.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.common.utils; import java.util.Set; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -public class FilterUtil { +public class FilterUtils { /** * Whether the message's tag matches consumerGroup's SubscriptionData * diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 88b9b4a9cd..b1e032c2f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -64,12 +64,22 @@ public class DefaultForwardClient extends AbstractForwardClient { return getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } - public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId, long timeoutMillis) { + public CompletableFuture getMaxOffset( + String brokerAddr, + String topic, + int queueId, + long timeoutMillis + ) { return getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); } - public CompletableFuture searchOffset(String brokerAddr, String topic, int queueId, long timestamp, - long timeoutMillis) { + public CompletableFuture searchOffset( + String brokerAddr, + String topic, + int queueId, + long timestamp, + long timeoutMillis + ) { return getClient().searchOffset(brokerAddr, topic, queueId, timestamp, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 03f4877313..263542b9b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -193,7 +193,8 @@ public class Converter { changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); + changeInvisibleTimeRequestHeader.setInvisibleTime( + delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); return changeInvisibleTimeRequestHeader; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java index d2a1bcd1b2..07d7ab9bf3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/ContextInterceptor.java @@ -23,7 +23,6 @@ import io.grpc.Metadata; import io.grpc.ServerCall; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; public class ContextInterceptor implements ServerInterceptor { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java index 698f75d00e..d106f8f0d2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java @@ -25,7 +25,6 @@ import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; import java.net.InetSocketAddress; import java.net.SocketAddress; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; public class HeaderInterceptor implements ServerInterceptor { @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index cb175d2ef9..5a672f43ea 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.interceptor; import io.grpc.Context; import io.grpc.Metadata; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 2072a21eae..0fa164afe4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -98,7 +98,7 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHand import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseFuture; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index 02c2003fb2..f2f20c517c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -32,7 +32,7 @@ import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index f9f3a24986..6d7adab3da 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -34,7 +34,7 @@ import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtil; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -156,7 +156,7 @@ public class PullMessageService extends BaseService { PullStatus status = result.getPullStatus(); if (status.equals(PullStatus.FOUND)) { List messageList = result.getMsgFoundList().stream() - .filter(msg -> FilterUtil.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. + .filter(msg -> FilterUtils.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. .map(Converter::buildMessage) .collect(Collectors.toList()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java index b6a5198a96..2586060019 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java @@ -27,25 +27,25 @@ public class FilterUtilTest { @Test public void testIsTagMatched() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); - assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); + assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); } @Test public void testIsTagNotMatched() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); - assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagB")).isFalse(); + assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagB")).isFalse(); } @Test public void testIsTagMatchedStar() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "*"); - assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); + assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); } @Test public void testIsTagNotMatchedNull() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); - assertThat(FilterUtil.isTagMatched(subscriptionData.getTagsSet(), null)).isFalse(); + assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), null)).isFalse(); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 093b0a47a6..6731ed8459 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -78,7 +78,7 @@ import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.store.MessageStore; From 1dc5b7c415d6408683bfecbf4176b1708c671f5e Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 18 Mar 2022 17:55:41 +0800 Subject: [PATCH 057/338] [ISSUE #3949] Improve readability. --- .../ProxyClientRemotingProcessor.java | 36 +++++++++---------- .../rocketmq/proxy/grpc/common/Converter.java | 17 ++++----- .../grpc/service/ClusterGrpcService.java | 23 +++++++----- .../service/cluster/TransactionService.java | 16 ++++----- .../proxy/common/utils/FilterUtilTest.java | 1 + 5 files changed, 49 insertions(+), 44 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java index 30567fdb74..3f217294f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java @@ -39,10 +39,8 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { } @Override - public RemotingCommand processRequest( - ChannelHandlerContext ctx, - RemotingCommand request - ) throws RemotingCommandException { + public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) + throws RemotingCommandException { if (request.getCode() == RequestCode.CHECK_TRANSACTION_STATE) { return this.checkTransactionState(ctx, request); } @@ -50,10 +48,8 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { } @Override - public RemotingCommand checkTransactionState( - ChannelHandlerContext ctx, - RemotingCommand request - ) throws RemotingCommandException { + public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, RemotingCommand request) + throws RemotingCommandException { final CheckTransactionStateRequestHeader requestHeader = (CheckTransactionStateRequestHeader) request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); final ByteBuffer byteBuffer = ByteBuffer.wrap(request.getBody()); @@ -61,18 +57,20 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { if (messageExt != null) { final String group = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); if (group != null) { - transactionStateChecker.checkTransactionState(new TransactionStateCheckRequest( - group, - requestHeader.getTranStateTableOffset(), - requestHeader.getCommitLogOffset(), - requestHeader.getMsgId(), - TransactionId.genFromBrokerTransactionId( - ctx.channel().remoteAddress(), - requestHeader.getTransactionId(), + transactionStateChecker.checkTransactionState( + new TransactionStateCheckRequest( + group, + requestHeader.getTranStateTableOffset(), requestHeader.getCommitLogOffset(), - requestHeader.getTranStateTableOffset()), - messageExt - )); + requestHeader.getMsgId(), + TransactionId.genFromBrokerTransactionId( + ctx.channel().remoteAddress(), + requestHeader.getTransactionId(), + requestHeader.getCommitLogOffset(), + requestHeader.getTranStateTableOffset()), + messageExt + ) + ); } } return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 263542b9b4..f60fac135f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -259,17 +259,15 @@ public class Converter { return endTransactionRequestHeader; } - public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTime) { + public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { Partition partition = request.getPartition(); String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); int queueId = partition.getId(); int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); - String expression = request.getFilterExpression() - .getExpression(); - String expressionType = Converter.buildExpressionType(request.getFilterExpression() - .getType()); + String expression = request.getFilterExpression().getExpression(); + String expressionType = Converter.buildExpressionType(request.getFilterExpression().getType()); PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); requestHeader.setConsumerGroup(groupName); @@ -279,7 +277,7 @@ public class Converter { requestHeader.setMaxMsgNums(request.getBatchSize()); requestHeader.setSysFlag(sysFlag); requestHeader.setCommitOffset(0L); - requestHeader.setSuspendTimeoutMillis(pollTime); + requestHeader.setSuspendTimeoutMillis(pollTimeoutInMillis); requestHeader.setSubscription(expression); requestHeader.setSubVersion(0L); requestHeader.setExpressionType(expressionType); @@ -296,22 +294,26 @@ public class Converter { } } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); + // set tag String tag = message.getSystemAttribute().getTag(); if (!"".equals(tag)) { messageWithHeader.setTags(tag); } + // set keys List keysList = message.getSystemAttribute().getKeysList(); if (keysList.size() > 0) { messageWithHeader.setKeys(keysList); } + // set message id String messageId = message.getSystemAttribute().getMessageId(); if ("".equals(messageId)) { throw new IllegalArgumentException("message id is empty"); } MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); + // set transaction property MessageType messageType = message.getSystemAttribute().getMessageType(); if (messageType.equals(MessageType.TRANSACTION)) { @@ -328,8 +330,7 @@ public class Converter { case DELAY_LEVEL: int delayLevel = message.getSystemAttribute().getDelayLevel(); if (delayLevel > 0) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_DELAY_TIME_LEVEL, - String.valueOf(delayLevel)); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(delayLevel)); } break; case DELIVERY_TIMESTAMP: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 4366b80c0b..889da0e2b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -68,9 +68,9 @@ import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; import org.slf4j.Logger; @@ -115,9 +115,11 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { this.clientService.heartbeat(ctx, request, channelManager); - return CompletableFuture.completedFuture(HeartbeatResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build()); + return CompletableFuture.completedFuture( + HeartbeatResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build() + ); } @Override @@ -194,13 +196,16 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { this.clientService.unregister(ctx, request, channelManager); - return CompletableFuture.completedFuture(NotifyClientTerminationResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build()); + return CompletableFuture.completedFuture( + NotifyClientTerminationResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build() + ); } - @Override public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { + @Override + public CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index 5e6060a36d..3484ddfa01 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -40,7 +40,7 @@ import org.apache.rocketmq.proxy.grpc.common.ResponseHook; public class TransactionService extends BaseService implements TransactionStateChecker { - private ChannelManager channelManager; + private final ChannelManager channelManager; private final ForwardProducer forwardProducer; private volatile ResponseHook checkTransactionStateHook = null; @@ -56,23 +56,23 @@ public class TransactionService extends BaseService implements TransactionStateC public void checkTransactionState(TransactionStateCheckRequest checkData) { try { List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); + // if clientIdList's size is 0, here will throw: java.lang.IllegalArgumentException: bound must be positive String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); String transactionId = checkData.getTransactionId().getProxyTransactionId(); Message message = Converter.buildMessage(checkData.getMessageExt()); - - PollCommandResponse commandResponse = PollCommandResponse.newBuilder() + PollCommandResponse response = PollCommandResponse.newBuilder() .setRecoverOrphanedTransactionCommand( RecoverOrphanedTransactionCommand.newBuilder() .setOrphanedTransactionalMessage(message) .setTransactionId(transactionId) .build() ).build(); - channel.writeAndFlush(commandResponse); + channel.writeAndFlush(response); if (this.checkTransactionStateHook != null) { - this.checkTransactionStateHook.beforeResponse(checkData, commandResponse, null); + this.checkTransactionStateHook.beforeResponse(checkData, response, null); } } catch (Throwable t) { if (this.checkTransactionStateHook != null) { @@ -88,8 +88,9 @@ public class TransactionService extends BaseService implements TransactionStateC endTransactionHook.beforeResponse(request, response, throwable); } }); + try { - EndTransactionRequestHeader requestHeader = this.convertToEndTransactionRequestHeader(ctx, request); + EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); this.forwardProducer.endTransaction(requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); future.complete(EndTransactionResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) @@ -100,8 +101,7 @@ public class TransactionService extends BaseService implements TransactionStateC return future; } - protected EndTransactionRequestHeader convertToEndTransactionRequestHeader(Context ctx, - EndTransactionRequest request) { + protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { return Converter.buildEndTransactionRequestHeader(request); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java index 2586060019..92ad3a362a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.common.utils; +import java.util.concurrent.ThreadLocalRandom; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.junit.Test; From 3f07761f60efd00ae2f809f049b9802912b5f781 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 18 Mar 2022 17:22:37 +0800 Subject: [PATCH 058/338] [ISSUE #3949] ack msg when tag not match; refactor client factory --- .../client/impl/MQClientAPIExtImpl.java | 19 +++++- .../ChangeInvisibleTimeRequestHeader.java | 11 ++++ .../proxy/common/utils/ProxyUtils.java | 2 + .../proxy/connector/ForwardProducer.java | 3 +- .../factory/AbstractClientFactory.java | 7 +- .../factory/AbstractMQClientFactory.java | 66 +++++++++++++++++++ .../factory/ForwardClientFactory.java | 10 ++- .../connector/factory/MQClientFactory.java | 34 +++------- .../factory/TransactionProducerFactory.java | 34 +++------- .../rocketmq/proxy/grpc/common/Converter.java | 6 ++ .../grpc/service/cluster/ConsumerService.java | 60 +++++++++++++++-- 11 files changed, 186 insertions(+), 66 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java index d77159d87d..8b0463bca6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -54,9 +54,13 @@ import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MQClientAPIExtImpl { + private static final Logger log = LoggerFactory.getLogger(MQClientAPIExtImpl.class); + private final MQClientAPIImpl mqClientAPI; private final ClientConfig clientConfig; @@ -75,6 +79,19 @@ public class MQClientAPIExtImpl { this.mqClientAPI.shutdown(); } + public void fetchNameServerAddr() { + this.mqClientAPI.fetchNameServerAddr(); + } + + public boolean updateNameServerAddressList() { + if (this.clientConfig.getNamesrvAddr() != null) { + this.mqClientAPI.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); + log.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); + return true; + } + return false; + } + protected static MQClientException processNullResponseErr(ResponseFuture responseFuture) { MQClientException ex; if (!responseFuture.isSendRequestOK()) { @@ -174,7 +191,7 @@ public class MQClientAPIExtImpl { long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.popMessageAsync(brokerAddr, brokerName, requestHeader, timeoutMillis, new PopCallback() { + this.mqClientAPI.popMessageAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new PopCallback() { @Override public void onSuccess(PopResult popResult) { future.complete(popResult); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java index a586e490cf..f01e89c725 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java @@ -94,4 +94,15 @@ public class ChangeInvisibleTimeRequestHeader implements CommandCustomHeader { this.queueId = queueId; } + @Override + public String toString() { + return "ChangeInvisibleTimeRequestHeader [" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + ", queueId=" + queueId + + ", extraInfo='" + extraInfo + '\'' + + ", offset=" + offset + + ", invisibleTime=" + invisibleTime + + ']'; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index f335cdfa0a..f7c05450b6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -20,4 +20,6 @@ import java.time.Duration; public class ProxyUtils { public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); + + public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index d35b65fd24..30bc4a939b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -86,14 +86,13 @@ public class ForwardProducer extends AbstractForwardClient { public CompletableFuture sendMessage(String address, String brokerName, Message msg, SendMessageRequestHeader requestHeader, long timeoutMillis) { CompletableFuture future = this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); - future.thenApply(sendResult -> { + return future.thenApply(sendResult -> { if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && !StringUtils.isEmpty(sendResult.getTransactionId())) { TransactionId transactionId = TransactionId.genFromBrokerTransactionId(address, sendResult); sendResult.setTransactionId(transactionId.getProxyTransactionId()); } return sendResult; }); - return future; } public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java index 7e0519097b..daae5bc2bd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.connector.factory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.slf4j.Logger; @@ -26,10 +27,12 @@ import org.slf4j.LoggerFactory; public abstract class AbstractClientFactory { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientFactory.class); + protected final ScheduledExecutorService scheduledExecutorService; protected Map cacheTable = new ConcurrentHashMap<>(); protected RPCHook rpcHook; - public AbstractClientFactory(RPCHook rpcHook) { + public AbstractClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { + this.scheduledExecutorService = scheduledExecutorService; this.rpcHook = rpcHook; } @@ -47,7 +50,6 @@ public abstract class AbstractClientFactory { return nettyClientConfig; } -// @Override public T getOne(String instanceName, int bootstrapWorkerThreads) { if (cacheTable.containsKey(instanceName)) { return cacheTable.get(instanceName); @@ -71,7 +73,6 @@ public abstract class AbstractClientFactory { return object; } -// @Override public void shutdownAll() { this.cacheTable.forEach((k, v) -> { try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java new file mode 100644 index 0000000000..c7417d4d46 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.connector.factory; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.remoting.RPCHook; + +public abstract class AbstractMQClientFactory extends AbstractClientFactory { + + public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, + RPCHook rpcHook) { + super(scheduledExecutorService, rpcHook); + } + + protected abstract ClientRemotingProcessor createClientRemotingProcessor(); + + @Override + protected MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { + ClientConfig clientConfig = new ClientConfig(); + clientConfig.setInstanceName(instanceName); + + return new MQClientAPIExtImpl( + createNettyClientConfig(bootstrapWorkerThreads), + createClientRemotingProcessor(), + rpcHook, + clientConfig + ); + } + + @Override + protected boolean tryStart(MQClientAPIExtImpl client) { + if (!client.updateNameServerAddressList()) { + this.scheduledExecutorService.scheduleAtFixedRate( + client::fetchNameServerAddr, + 1000 * 10, + 1000 * 60 * 2, + TimeUnit.MILLISECONDS + ); + } + client.start(); + return true; + } + + @Override + protected void shutdown(MQClientAPIExtImpl client) { + client.shutdown(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java index 08b43acf2c..350111011a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java @@ -16,6 +16,9 @@ */ package org.apache.rocketmq.proxy.connector.factory; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; @@ -35,8 +38,11 @@ public class ForwardClientFactory implements StartAndShutdown { public ForwardClientFactory(TransactionStateChecker transactionStateChecker) { this.init(); - this.mqClientFactory = new MQClientFactory(this.rpcHook); - this.transactionalProducerFactory = new TransactionProducerFactory(this.rpcHook, transactionStateChecker); + ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder().setNameFormat("ForwardClientFactoryScheduledThread" + "-%d").build() + ); + this.mqClientFactory = new MQClientFactory(scheduledExecutorService, this.rpcHook); + this.transactionalProducerFactory = new TransactionProducerFactory(scheduledExecutorService, this.rpcHook, transactionStateChecker); } private void init() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java index 3b9a75f33b..07484bd54b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java @@ -16,38 +16,20 @@ */ package org.apache.rocketmq.proxy.connector.factory; -import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; import org.apache.rocketmq.proxy.connector.processor.DoNothingClientRemotingProcessor; import org.apache.rocketmq.remoting.RPCHook; -public class MQClientFactory extends AbstractClientFactory { +public class MQClientFactory extends AbstractMQClientFactory { - public MQClientFactory(RPCHook rpcHook) { - super(rpcHook); + public MQClientFactory(ScheduledExecutorService scheduledExecutorService, + RPCHook rpcHook) { + super(scheduledExecutorService, rpcHook); } @Override - protected MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.setInstanceName(instanceName); - - return new MQClientAPIExtImpl( - createNettyClientConfig(bootstrapWorkerThreads), - new DoNothingClientRemotingProcessor(null), - rpcHook, - clientConfig - ); - } - - @Override - protected boolean tryStart(MQClientAPIExtImpl client) { - client.start(); - return true; - } - - @Override - protected void shutdown(MQClientAPIExtImpl client) { - client.shutdown(); + protected ClientRemotingProcessor createClientRemotingProcessor() { + return new DoNothingClientRemotingProcessor(null); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java index a97727c11d..92a4006479 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java @@ -16,41 +16,23 @@ */ package org.apache.rocketmq.proxy.connector.factory; -import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; import org.apache.rocketmq.proxy.connector.processor.ProxyClientRemotingProcessor; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.remoting.RPCHook; -public class TransactionProducerFactory extends AbstractClientFactory { +public class TransactionProducerFactory extends AbstractMQClientFactory { private final TransactionStateChecker transactionStateChecker; - public TransactionProducerFactory(RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { - super(rpcHook); + public TransactionProducerFactory(ScheduledExecutorService scheduledExecutorService, + RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { + super(scheduledExecutorService, rpcHook); this.transactionStateChecker = transactionStateChecker; } @Override - public MQClientAPIExtImpl newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.setInstanceName(instanceName); - - return new MQClientAPIExtImpl( - createNettyClientConfig(bootstrapWorkerThreads), - new ProxyClientRemotingProcessor(this.transactionStateChecker), - rpcHook, - clientConfig - ); - } - - @Override - protected boolean tryStart(MQClientAPIExtImpl client) { - client.start(); - return true; - } - - @Override - protected void shutdown(MQClientAPIExtImpl client) { - client.shutdown(); + protected ClientRemotingProcessor createClientRemotingProcessor() { + return new ProxyClientRemotingProcessor(this.transactionStateChecker); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index f60fac135f..e1bd1f35d6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -88,6 +88,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.slf4j.Logger; @@ -140,6 +141,11 @@ public class Converter { String topicName = Converter.getResourceNameWithNamespace(topic); int queueId = partition.getId(); int maxMessageNumbers = request.getBatchSize(); + if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { + LOGGER.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", + maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); + maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; + } long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); ConsumePolicy policy = request.getConsumePolicy(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index fb4d10bb7b..21b8edc980 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -34,6 +34,8 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.utils.FilterUtil; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -57,6 +59,7 @@ public class ConsumerService extends BaseService { private volatile ReadQueueSelector readQueueSelector; private volatile ResponseHook receiveMessageHook = null; + private volatile ResponseHook ackNoMatchedMessageHook = null; private volatile ResponseHook ackMessageHook = null; private volatile ResponseHook nackMessageHook = null; @@ -87,13 +90,18 @@ public class ConsumerService extends BaseService { messageQueue.getBrokerName(), requestHeader, requestHeader.getPollTime()); - popResultFuture.thenAccept(result -> { - try { - future.complete(convertToReceiveMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { + popResultFuture + .thenAccept(result -> { + try { + future.complete(convertToReceiveMessageResponse(ctx, request, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { future.completeExceptionally(throwable); - } - }); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } @@ -101,6 +109,9 @@ public class ConsumerService extends BaseService { } protected PopMessageRequestHeader convertToPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { + // check filterExpression is correct or not + Converter.buildSubscriptionData(Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + long timeRemaining = ctx.getDeadline() .timeRemaining(TimeUnit.MILLISECONDS); long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); @@ -112,6 +123,8 @@ public class ConsumerService extends BaseService { } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { + SubscriptionData subscriptionData = Converter.buildSubscriptionData( + Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); PopStatus status = result.getPopStatus(); switch (status) { case FOUND: @@ -130,6 +143,10 @@ public class ConsumerService extends BaseService { List messages = new ArrayList<>(); for (MessageExt messageExt : result.getMsgFoundList()) { + if (FilterUtil.isTagNotMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + this.ackNoMatchedMessage(ctx, request, messageExt); + continue; + } messages.add(Converter.buildMessage(messageExt)); } @@ -139,6 +156,32 @@ public class ConsumerService extends BaseService { .build(); } + protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { + CompletableFuture future = new CompletableFuture<>(); + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); + ackMessageRequestHeader.setConsumerGroup(Converter.getResourceNameWithNamespace(request.getGroup())); + ackMessageRequestHeader.setTopic(messageExt.getTopic()); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + + future = this.writeConsumer.ackMessage(brokerAddr, ackMessageRequestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } catch (Throwable t) { + future.completeExceptionally(t); + } + future.whenComplete((ackResult, throwable) -> { + if (ackNoMatchedMessageHook != null) { + ackNoMatchedMessageHook.beforeResponse(ackMessageRequestHeader, ackResult, throwable); + } + }); + } + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -242,6 +285,11 @@ public class ConsumerService extends BaseService { this.receiveMessageHook = receiveMessageHook; } + public void setAckNoMatchedMessageHook( + ResponseHook ackNoMatchedMessageHook) { + this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; + } + public void setAckMessageHook( ResponseHook ackMessageHook) { this.ackMessageHook = ackMessageHook; From 2cea9131b19cb2be01f742a45d58ccd94c104087 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 18 Mar 2022 18:45:31 +0800 Subject: [PATCH 059/338] [ISSUE #3949] forward message to dlq --- .../client/impl/MQClientAPIExtImpl.java | 2 +- .../common/consumer/ReceiptHandle.java | 51 ++++++++++--------- .../rocketmq/proxy/grpc/common/Converter.java | 25 +++++++-- .../proxy/grpc/service/LocalGrpcService.java | 3 +- .../grpc/service/cluster/ConsumerService.java | 50 +++++++++++++++--- .../grpc/service/LocalGrpcServiceTest.java | 8 +-- 6 files changed, 96 insertions(+), 43 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java index 8b0463bca6..a9474fd37e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java @@ -171,7 +171,7 @@ public class MQClientAPIExtImpl { long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); try { - RemotingCommand request = RemotingCommand.createResponseCommandWithHeader(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { RemotingCommand response = responseFuture.getResponseCommand(); if (response != null) { diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java index 20f573e514..ee7f9a83bf 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.common.consumer; import java.util.Arrays; import java.util.List; -import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; @@ -32,7 +32,7 @@ public class ReceiptHandle { private final long invisibleTime; private final long nextVisibleTime; private final int reviveQueueId; - private final String topic; + private final String topicType; private final String brokerName; private final int queueId; private final long offset; @@ -40,12 +40,8 @@ public class ReceiptHandle { private final String receiptHandle; public String encode() { - String t = NORMAL_TOPIC; - if (topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { - t = RETRY_TOPIC; - } return startOffset + SEPARATOR + retrieveTime + SEPARATOR + invisibleTime + SEPARATOR + reviveQueueId - + SEPARATOR + t + SEPARATOR + brokerName + SEPARATOR + queueId + SEPARATOR + offset + SEPARATOR + + SEPARATOR + topicType + SEPARATOR + brokerName + SEPARATOR + queueId + SEPARATOR + offset + SEPARATOR + commitLogOffset; } @@ -84,7 +80,7 @@ public class ReceiptHandle { .retrieveTime(retrieveTime) .invisibleTime(invisibleTime) .reviveQueueId(reviveQueueId) - .topic(topic) + .topicType(topic) .brokerName(brokerName) .queueId(queueId) .offset(offset) @@ -94,14 +90,14 @@ public class ReceiptHandle { } ReceiptHandle(final long startOffset, final long retrieveTime, final long invisibleTime, final long nextVisibleTime, - final int reviveQueueId, final String topic, final String brokerName, final int queueId, final long offset, + final int reviveQueueId, final String topicType, final String brokerName, final int queueId, final long offset, final long commitLogOffset, final String receiptHandle) { this.startOffset = startOffset; this.retrieveTime = retrieveTime; this.invisibleTime = invisibleTime; this.nextVisibleTime = nextVisibleTime; this.reviveQueueId = reviveQueueId; - this.topic = topic; + this.topicType = topicType; this.brokerName = brokerName; this.queueId = queueId; this.offset = offset; @@ -115,12 +111,11 @@ public class ReceiptHandle { private long invisibleTime; private long nextVisibleTime; private int reviveQueueId; - private String topic; + private String topicType; private String brokerName; private int queueId; private long offset; private long commitLogOffset; - private String type; private String receiptHandle; ReceiptHandleBuilder() { @@ -151,8 +146,8 @@ public class ReceiptHandle { return this; } - public ReceiptHandle.ReceiptHandleBuilder topic(final String topic) { - this.topic = topic; + public ReceiptHandle.ReceiptHandleBuilder topicType(final String topic) { + this.topicType = topic; return this; } @@ -176,11 +171,6 @@ public class ReceiptHandle { return this; } - public ReceiptHandle.ReceiptHandleBuilder type(final String type) { - this.type = type; - return this; - } - public ReceiptHandle.ReceiptHandleBuilder receiptHandle(final String receiptHandle) { this.receiptHandle = receiptHandle; return this; @@ -188,12 +178,12 @@ public class ReceiptHandle { public ReceiptHandle build() { return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.nextVisibleTime, - this.reviveQueueId, this.topic, this.brokerName, this.queueId, this.offset, this.commitLogOffset, this.receiptHandle); + this.reviveQueueId, this.topicType, this.brokerName, this.queueId, this.offset, this.commitLogOffset, this.receiptHandle); } - @java.lang.Override - public java.lang.String toString() { - return "ReceiptHandle.ReceiptHandleBuilder(startOffset=" + this.startOffset + ", retrieveTime=" + this.retrieveTime + ", invisibleTime=" + this.invisibleTime + ", nextVisibleTime=" + this.nextVisibleTime + ", reviveQueueId=" + this.reviveQueueId + ", topic=" + this.topic + ", brokerName=" + this.brokerName + ", queueId=" + this.queueId + ", offset=" + this.offset + ", commitLogOffset=" + this.commitLogOffset + ", type=" + this.type + ", receiptHandle=" + this.receiptHandle + ")"; + @Override + public String toString() { + return "ReceiptHandle.ReceiptHandleBuilder(startOffset=" + this.startOffset + ", retrieveTime=" + this.retrieveTime + ", invisibleTime=" + this.invisibleTime + ", nextVisibleTime=" + this.nextVisibleTime + ", reviveQueueId=" + this.reviveQueueId + ", topic=" + this.topicType + ", brokerName=" + this.brokerName + ", queueId=" + this.queueId + ", offset=" + this.offset + ", commitLogOffset=" + this.commitLogOffset + ", receiptHandle=" + this.receiptHandle + ")"; } } @@ -221,8 +211,8 @@ public class ReceiptHandle { return this.reviveQueueId; } - public String getTopic() { - return this.topic; + public String getTopicType() { + return this.topicType; } public String getBrokerName() { @@ -244,4 +234,15 @@ public class ReceiptHandle { public String getReceiptHandle() { return this.receiptHandle; } + + public boolean isRetryTopic() { + return RETRY_TOPIC.equals(topicType); + } + + public String getRealTopic(String topic, String groupName) { + if (isRetryTopic()) { + return KeyBuilder.buildPopRetryTopic(topic, groupName); + } + return topic; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index e1bd1f35d6..d6cab5b5c3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -179,7 +179,7 @@ public class Converter { AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); ackMessageRequestHeader.setConsumerGroup(groupName); - ackMessageRequestHeader.setTopic(topicName); + ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); ackMessageRequestHeader.setQueueId(handle.getQueueId()); ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); ackMessageRequestHeader.setOffset(handle.getOffset()); @@ -195,7 +195,7 @@ public class Converter { ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(topicName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); @@ -213,7 +213,7 @@ public class Converter { ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(topicName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); @@ -233,7 +233,24 @@ public class Converter { consumerSendMsgBackRequestHeader.setGroup(groupName); consumerSendMsgBackRequestHeader.setDelayLevel(-1); consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); - consumerSendMsgBackRequestHeader.setOriginMsgId(topicName); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); + return consumerSendMsgBackRequestHeader; + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( + NackMessageRequest request) { + String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String receiptHandleStr = request.getReceiptHandle(); + ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); return consumerSendMsgBackRequestHeader; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 0fa164afe4..89be32779e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -514,6 +514,7 @@ public class LocalGrpcService implements GrpcForwardService { SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request); + ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -530,7 +531,7 @@ public class LocalGrpcService implements GrpcForwardService { .retrieveTime(responseHeader.getPopTime()) .invisibleTime(responseHeader.getInvisibleTime()) .reviveQueueId(responseHeader.getReviveQid()) - .topic(Converter.getResourceNameWithNamespace(request.getTopic())) + .topicType(receiptHandle.getTopicType()) .brokerName(brokerController.getBrokerConfig().getBrokerName()) .queueId(requestHeader.getQueueId()) .offset(requestHeader.getOffset()) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 21b8edc980..d6975e6892 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -33,12 +33,14 @@ import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtil; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; @@ -51,11 +53,13 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { private final ForwardReadConsumer readConsumer; private final ForwardWriteConsumer writeConsumer; + private final ForwardProducer producer; private volatile ReadQueueSelector readQueueSelector; private volatile ResponseHook receiveMessageHook = null; @@ -69,6 +73,7 @@ public class ConsumerService extends BaseService { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); + this.producer = connectorManager.getForwardProducer(); this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); this.delayPolicy = DelayPolicy.build(ConfigurationManager.getProxyConfig().getMessageDelayLevel()); @@ -143,7 +148,7 @@ public class ConsumerService extends BaseService { List messages = new ArrayList<>(); for (MessageExt messageExt : result.getMsgFoundList()) { - if (FilterUtil.isTagNotMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { this.ackNoMatchedMessage(ctx, request, messageExt); continue; } @@ -239,10 +244,29 @@ public class ConsumerService extends BaseService { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - ChangeInvisibleTimeRequestHeader requestHeader = this.convertToChangeInvisibleTimeRequestHeader(ctx, request); - CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, - ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - resultFuture + if (request.getDeliveryAttempt() >= request.getMaxDeliveryAttempts()) { + CompletableFuture resultFuture = this.producer.sendMessageBack( + brokerAddr, + this.convertToConsumerSendMsgBackToDLQRequestHeader(ctx, request), + ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + resultFuture + .thenAccept(result -> { + try { + future.complete(convertToNackMessageResponse(ctx, request, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { + throwable.printStackTrace(); + future.completeExceptionally(throwable); + return null; + }); + } else { + ChangeInvisibleTimeRequestHeader requestHeader = this.convertToChangeInvisibleTimeRequestHeader(ctx, request); + CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, + ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + resultFuture .thenAccept(result -> { try { future.complete(convertToNackMessageResponse(ctx, request, result)); @@ -254,6 +278,7 @@ public class ConsumerService extends BaseService { future.completeExceptionally(throwable); return null; }); + } } catch (Throwable t) { future.completeExceptionally(t); } @@ -264,6 +289,10 @@ public class ConsumerService extends BaseService { return Converter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); } + protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request) { + return Converter.buildConsumerSendMsgBackToDLQRequestHeader(request); + } + protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return NackMessageResponse.newBuilder() @@ -275,8 +304,13 @@ public class ConsumerService extends BaseService { .build(); } - public void setReadQueueSelector( - ReadQueueSelector readQueueSelector) { + protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, RemotingCommand sendMsgBackToDLQResult) { + return NackMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) + .build(); + } + + public void setReadQueueSelector(ReadQueueSelector readQueueSelector) { this.readQueueSelector = readQueueSelector; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 6731ed8459..e473b039c9 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -295,7 +295,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .invisibleTime(1000L) .nextVisibleTime(1000L) .reviveQueueId(0) - .topic("topic") + .topicType("topic") .brokerName("brokerName") .queueId(0) .offset(0L) @@ -328,7 +328,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .invisibleTime(1000L) .nextVisibleTime(1000L) .reviveQueueId(0) - .topic("topic") + .topicType("topic") .brokerName("brokerName") .queueId(0) .offset(0L) @@ -357,7 +357,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .invisibleTime(1000L) .nextVisibleTime(1000L) .reviveQueueId(0) - .topic("topic") + .topicType("topic") .brokerName("brokerName") .queueId(0) .offset(0L) @@ -511,7 +511,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .invisibleTime(invisibleTime) .nextVisibleTime(1000L) .reviveQueueId(0) - .topic("topic") + .topicType("topic") .brokerName("brokerName") .queueId(queueId) .offset(offset) From caaadca11c94b587a09a7cac3395ec806bb50cf9 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 18 Mar 2022 19:17:18 +0800 Subject: [PATCH 060/338] [ISSUE #3949] Improve readability. --- .../rocketmq/proxy/grpc/common/Converter.java | 20 +++++++++---------- .../grpc/service/cluster/ClientService.java | 17 ++++++++++------ .../DefaultAssignmentQueueSelector.java | 3 ++- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index d6cab5b5c3..7b0e978e60 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -503,10 +503,8 @@ public class Converter { public static Message buildMessage(MessageExt messageExt) { Map userAttributes = buildUserAttributes(messageExt); SystemAttribute systemAttributes = buildSystemAttributes(messageExt); - Resource topic = Resource.newBuilder() - .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) - .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) - .build(); + Resource topic = buildResource(messageExt.getTopic()); + return Message.newBuilder() .setTopic(topic) .putAllUserAttribute(userAttributes) @@ -641,12 +639,7 @@ public class Converter { // publisher_group String producerGroup = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); if (producerGroup != null) { - String namespaceId = NamespaceUtil.getNamespaceFromResource(producerGroup); - String group = NamespaceUtil.withoutNamespace(producerGroup); - systemAttributeBuilder.setProducerGroup(Resource.newBuilder() - .setResourceNamespace(namespaceId) - .setName(group) - .build()); + systemAttributeBuilder.setProducerGroup(buildResource(producerGroup)); } // trace context @@ -690,6 +683,13 @@ public class Converter { return consumeMessageDirectlyResult; } + public static Resource buildResource(String resourceNameWithNamespace) { + return Resource.newBuilder() + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) + .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) + .build(); + } + public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(NotifyClientTerminationRequest request) { UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); header.setClientID(request.getClientId()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index f2f20c517c..9872bd35c3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -24,6 +24,9 @@ import apache.rocketmq.v1.PollCommandRequest; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.Resource; import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; @@ -32,16 +35,12 @@ import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - public class ClientService extends BaseService { private static final Logger log = LoggerFactory.getLogger(ClientService.class); @@ -52,7 +51,12 @@ public class ClientService extends BaseService { private final ProducerManager producerManager; private final PollCommandResponseManager pollCommandResponseManager; - public ClientService(ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager, PollCommandResponseManager pollCommandResponseManager) { + public ClientService( + ConnectorManager connectorManager, + ScheduledExecutorService scheduledExecutorService, + ChannelManager channelManager, + PollCommandResponseManager pollCommandResponseManager + ) { super(connectorManager); scheduledExecutorService.scheduleWithFixedDelay(this::scanNotActiveChannel, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); this.channelManager = channelManager; @@ -70,6 +74,7 @@ public class ClientService extends BaseService { if (request.hasProducerData()) { String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId, pollCommandResponseManager); + //TODO: Use the faked MQ Version ? ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); producerManager.registerProducer(producerGroup, clientChannelInfo); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java index 1738cb1f3e..92ea26eb5a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java @@ -34,7 +34,8 @@ public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @Override public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { - MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topicName); return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); } } \ No newline at end of file From 3036cf421d72c6ec805c1355e62f7e6623645298 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 21 Mar 2022 15:54:13 +0800 Subject: [PATCH 061/338] [ISSUE #3949] Add className in createChannel --- .../apache/rocketmq/proxy/channel/ChannelManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 8fa53b3d7b..9a25d1c45e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -50,7 +50,7 @@ public class ChannelManager { } public T createChannel(Supplier creator, Class clazz) { - return createChannel(anonymousChannelId(), creator, clazz); + return createChannel(anonymousChannelId(clazz.getName()), creator, clazz); } public T createChannel(String clientId, Supplier creator, Class clazz) { @@ -96,6 +96,14 @@ public class ChannelManager { return clientHost + "@" + localAddress; } + private String anonymousChannelId(String className) { + final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.REMOTE_ADDRESS); + final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + .get(InterceptorConstants.LOCAL_ADDRESS); + return className + "@" + clientHost + "@" + localAddress; + } + public static SimpleChannel createSimpleChannelDirectly() { final String clientHost = InterceptorConstants.METADATA.get(Context.current()) .get(InterceptorConstants.REMOTE_ADDRESS); From 2824c686dbf7c5d044c5ee9059dfbcd66833aad9 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 21 Mar 2022 19:09:28 +0800 Subject: [PATCH 062/338] [ISSUE #3949] Refector GrpcBaseTest --- .../rocketmq/proxy/HealthCheckServer.java | 4 +- .../apache/rocketmq/proxy/ProxyStartup.java | 38 +++++--- .../rocketmq/proxy/grpc/GrpcServer.java | 3 +- .../proxy/grpc/service/LocalGrpcService.java | 24 ++--- .../grpc/service/cluster/RouteService.java | 3 +- .../rocketmq/test/base/GrpcBaseTest.java | 90 ++++++++++++++++++- .../rocketmq/test/proxy/LocalGrpcTest.java | 79 ++++++---------- 7 files changed, 158 insertions(+), 83 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java index ed5e977a39..789a0dcf29 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -23,6 +23,7 @@ import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -39,8 +40,9 @@ public class HealthCheckServer implements StartAndShutdown { } @Override - public void shutdown() { + public void shutdown() throws InterruptedException { this.healthChecker.stop(0); + Thread.sleep(TimeUnit.SECONDS.toMillis(ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds())); } static class HealthCheckHandler implements HttpHandler { 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 808d748b7b..810fd8c1ed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -21,11 +21,12 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import java.util.Date; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.BrokerStartup; import org.apache.rocketmq.client.log.ClientLogger; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; @@ -39,6 +40,13 @@ import org.slf4j.LoggerFactory; public class ProxyStartup { private static final Logger log = LoggerFactory.getLogger(ProxyStartup.class); + private static final ProxyStartAndShutdown proxyStartAndShutdown = new ProxyStartAndShutdown(); + + private static class ProxyStartAndShutdown extends AbstractStartAndShutdown { + @Override public void appendStartAndShutdown(StartAndShutdown startAndShutdown) { + super.appendStartAndShutdown(startAndShutdown); + } + } public static void main(String[] args) { try { @@ -51,26 +59,19 @@ public class ProxyStartup { // create and start grpcServer GrpcServer grpcServer = createGrpcServer(); - grpcServer.start(); + proxyStartAndShutdown.appendStartAndShutdown(grpcServer); // health check server final HealthCheckServer healthCheckServer = new HealthCheckServer(); - healthCheckServer.start(); + proxyStartAndShutdown.appendStartAndShutdown(healthCheckServer); Runtime.getRuntime().addShutdownHook(new Thread(() -> { log.info("try to shutdown server"); try { - healthCheckServer.shutdown(); - Thread.sleep(TimeUnit.SECONDS.toMillis(ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds())); + proxyStartAndShutdown.shutdown(); } catch (Exception e) { - log.error("err when shutdown healthCheckServer", e); - } - - try { - grpcServer.shutdown(); - } catch (Exception e) { - log.error("err when shutdown grpc server", e); + log.error("err when shutdown proxy", e); } })); } catch (Exception e) { @@ -84,20 +85,29 @@ public class ProxyStartup { log.info(new Date() + "rmq-proxy startup successfully"); } - private static GrpcServer createGrpcServer() throws RuntimeException { + private static GrpcServer createGrpcServer() throws Exception { GrpcForwardService grpcService; String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); if (ProxyMode.isClusterMode(proxyModeStr)) { grpcService = new ClusterGrpcService(); } else if (ProxyMode.isLocalMode(proxyModeStr)) { BrokerController brokerController = createBrokerController(); + StartAndShutdown brokerControllerWrapper = new StartAndShutdown() { + @Override public void start() throws Exception { + brokerController.start(); + } + + @Override public void shutdown() throws Exception { + brokerController.shutdown(); + } + }; + proxyStartAndShutdown.appendStartAndShutdown(brokerControllerWrapper); grpcService = new LocalGrpcService(brokerController); } else { throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); } return new GrpcServer(grpcService); - } private static BrokerController createBrokerController() { 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 b2b0dafb38..c5e318a245 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 @@ -31,6 +31,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; @@ -38,7 +39,7 @@ import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class GrpcServer { +public class GrpcServer implements StartAndShutdown { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final io.grpc.Server server; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 89be32779e..ce4e7f78b1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -86,23 +86,25 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; -import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.common.Converter; import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseFuture; import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; @@ -111,7 +113,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalGrpcService implements GrpcForwardService { +public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final BrokerController brokerController; @@ -130,6 +132,8 @@ public class LocalGrpcService implements GrpcForwardService { this.pollCommandResponseManager = new PollCommandResponseManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); + this.appendStartAndShutdown(connectorManager); + this.appendStartAndShutdown(new LocalGrpcServiceStartAndShutdown()); } @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -547,14 +551,14 @@ public class LocalGrpcService implements GrpcForwardService { return future; } - @Override public void start() throws Exception { - this.brokerController.start(); - this.scheduledExecutorService.scheduleWithFixedDelay(this::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); - } + private class LocalGrpcServiceStartAndShutdown implements StartAndShutdown { + @Override public void start() throws Exception { + LocalGrpcService.this.scheduledExecutorService.scheduleWithFixedDelay(LocalGrpcService.this::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); + } - @Override public void shutdown() throws Exception { - this.scheduledExecutorService.shutdown(); - this.brokerController.shutdown(); + @Override public void shutdown() throws Exception { + LocalGrpcService.this.scheduledExecutorService.shutdown(); + } } private void scanAndCleanChannels() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index e7c64036b5..37d4acb047 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -41,6 +41,7 @@ import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; @@ -293,7 +294,7 @@ public class RouteService extends BaseService { .setScheme(AddressScheme.IPv4) .addAddresses( Address.newBuilder() - .setPort(hostAndPort.getPort()) + .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) .setHost(hostAndPort.getHost()) ) .build()) diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java index 25729bf16e..271dc0b75c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java @@ -17,6 +17,20 @@ package org.apache.rocketmq.test.base; +import apache.rocketmq.v1.Message; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v1.SystemAttribute; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.rpc.Code; import io.grpc.Channel; import io.grpc.ServerInterceptors; import io.grpc.ServerServiceDefinition; @@ -31,13 +45,14 @@ import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.junit.Rule; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; -@RunWith(MockitoJUnitRunner.class) +import static org.assertj.core.api.Assertions.assertThat; + public class GrpcBaseTest extends BaseConf { /** * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. @@ -45,6 +60,8 @@ public class GrpcBaseTest extends BaseConf { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + private static final int defaultQueueNums = 8; + protected Channel setUpServer(apache.rocketmq.v1.MessagingServiceGrpc.MessagingServiceImplBase serverImpl, int port, boolean enableInterceptor) throws IOException, CertificateException { SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); @@ -75,4 +92,71 @@ public class GrpcBaseTest extends BaseConf { ) .build()); } + + public QueryRouteRequest buildQueryRouteRequest(String topic) { + return QueryRouteRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .build(); + } + + public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { + return SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId(messageId) + .setPartitionId(0) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build(); + } + + public ReceiveMessageRequest buildReceiveMessageRequest(String group, String topic) { + return ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setId(0) + .build()) + .setBatchSize(16) + .setInvisibleDuration(Duration.newBuilder() + .setSeconds(3) + .build()) + .setInitializationTimestamp(Timestamp.newBuilder() + .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) + .build()) + .build(); + } + + public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { + assertThat(response.getCommon().getStatus().getCode()).isEqualTo(Code.OK_VALUE); + assertThat(response.getPartitionsList().size()).isEqualTo(brokerSize * defaultQueueNums); + assertThat(response.getPartitions(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); + } + + public void assertSendMessage(SendMessageResponse response, String messageId) { + assertThat(response.getCommon() + .getStatus() + .getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(response.getMessageId()).isEqualTo(messageId); + } + + public void assertReceiveMessage(ReceiveMessageResponse response, String messageId) { + assertThat(response.getCommon() + .getStatus() + .getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(response.getMessagesCount()).isEqualTo(1); + assertThat(response.getMessages(0) + .getSystemAttribute() + .getMessageId()).isEqualTo(messageId); + } } \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java index 387764ad3b..16e3d54326 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java @@ -17,19 +17,10 @@ package org.apache.rocketmq.test.proxy; -import apache.rocketmq.v1.Message; import apache.rocketmq.v1.MessagingServiceGrpc; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.QueryRouteResponse; import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; -import apache.rocketmq.v1.SystemAttribute; -import com.google.protobuf.ByteString; -import com.google.protobuf.Duration; -import com.google.protobuf.Timestamp; -import com.google.rpc.Code; import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; @@ -37,15 +28,16 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; import org.apache.rocketmq.test.base.GrpcBaseTest; +import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; -import static org.assertj.core.api.Assertions.assertThat; public class LocalGrpcTest extends GrpcBaseTest { private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + private LocalGrpcService localGrpcService; @Before public void setUp() throws Exception { @@ -57,56 +49,37 @@ public class LocalGrpcTest extends GrpcBaseTest { System.setProperty(RMQ_PROXY_HOME, mockProxyHome); ConfigurationManager.initEnv(); ConfigurationManager.intConfig(); - GrpcMessagingProcessor processor = new GrpcMessagingProcessor(new LocalGrpcService(brokerController1)); ConfigurationManager.getProxyConfig().setGrpcServerPort(8082); + ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + localGrpcService = new LocalGrpcService(brokerController1); + localGrpcService.start(); + GrpcMessagingProcessor processor = new GrpcMessagingProcessor(localGrpcService); Channel channel = setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); blockingStub = MessagingServiceGrpc.newBlockingStub(channel); } + @After + public void clean() throws Exception { + localGrpcService.shutdown(); + shutdown(); + } + + @Test + public void testQueryRoute() { + String topic = initTopic(); + QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); + assertQueryRoute(response, brokerControllerList.size()); + } + @Test public void testSendReceiveMessage() { String group = "group"; - SendMessageResponse sendResponse = blockingStub.sendMessage(SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setName(broker1Name) - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId(createUniqID()) - .setPartitionId(0) - .build()) - .setBody(ByteString.copyFromUtf8("123")) - .build()) - .build()); - assertThat(sendResponse.getCommon() - .getStatus() - .getCode()).isEqualTo(Code.OK.getNumber()); - String messageId = sendResponse.getMessageId(); + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(broker1Name, messageId)); + assertSendMessage(sendResponse, messageId); + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) - .receiveMessage(ReceiveMessageRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName(group) - .build()) - .setPartition(Partition.newBuilder() - .setTopic(Resource.newBuilder() - .setName(broker1Name) - .build()) - .setId(0) - .build()) - .setBatchSize(16) - .setInvisibleDuration(Duration.newBuilder() - .setSeconds(3) - .build()) - .setInitializationTimestamp(Timestamp.newBuilder() - .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) - .build()) - .build()); - assertThat(receiveResponse.getCommon() - .getStatus() - .getCode()).isEqualTo(Code.OK.getNumber()); - assertThat(receiveResponse.getMessagesCount()).isEqualTo(1); - assertThat(receiveResponse.getMessages(0) - .getSystemAttribute() - .getMessageId()).isEqualTo(messageId); + .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); + assertReceiveMessage(receiveResponse, messageId); } } From 4c8283c9590b8f6af307f0e0cdae271494b635e8 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 21 Mar 2022 19:32:37 +0800 Subject: [PATCH 063/338] [ISSUE #3949] can create transactionId when orgTransactionId is empty --- .../proxy/connector/ForwardProducer.java | 5 +- .../connector/transaction/TransactionId.java | 13 +++- .../rocketmq/proxy/grpc/common/Converter.java | 1 - .../transaction/TransactionIdTest.java | 52 +++++++++++++++ .../rocketmq/test/base/GrpcBaseTest.java | 8 +++ .../rocketmq/test/proxy/ClusterGrpcTest.java | 64 +++++++++++++++++++ 6 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java create mode 100644 test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 30bc4a939b..8facf9a8e4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; -import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; @@ -26,6 +25,7 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; @@ -87,7 +87,8 @@ public class ForwardProducer extends AbstractForwardClient { SendMessageRequestHeader requestHeader, long timeoutMillis) { CompletableFuture future = this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); return future.thenApply(sendResult -> { - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && !StringUtils.isEmpty(sendResult.getTransactionId())) { + int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { TransactionId transactionId = TransactionId.genFromBrokerTransactionId(address, sendResult); sendResult.setTransactionId(transactionId.getProxyTransactionId()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index a4daec0139..b909fbecd3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -23,6 +23,7 @@ import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Objects; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.common.message.MessageDecoder; @@ -70,7 +71,10 @@ public class TransactionId { public static TransactionId genFromBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, long commitLogOffset, long tranStateTableOffset) { - byte[] orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); + byte[] orgTransactionIdByte = new byte[0]; + if (StringUtils.isNotBlank(orgTransactionId)) { + orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); + } ByteBuffer byteBuffer = ByteBuffer.allocate(8 + 4 + orgTransactionIdByte.length + 8 + 8); byteBuffer.put(MessageExt.socketAddress2ByteBuffer(brokerAddr)); @@ -100,8 +104,11 @@ public class TransactionId { SocketAddress brokerAddr = new InetSocketAddress(InetAddress.getByAddress(ip), port); int orgTransactionIdLen = byteBuffer.getInt(); - byte[] orgTransactionIdByte = new byte[orgTransactionIdLen]; - byteBuffer.get(orgTransactionIdByte); + byte[] orgTransactionIdByte = new byte[0]; + if (orgTransactionIdLen > 0) { + orgTransactionIdByte = new byte[orgTransactionIdLen]; + byteBuffer.get(orgTransactionIdByte); + } long commitLogOffset = byteBuffer.getLong(); long tranStateTableOffset = byteBuffer.getLong(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java index 7b0e978e60..40591bfb0d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/Converter.java @@ -344,7 +344,6 @@ public class Converter { Duration transactionResolveDelay = message.getSystemAttribute().getOrphanedTransactionRecoveryPeriod(); - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_CHECK_TIMES, String.valueOf(15)); MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, String.valueOf(Durations.toSeconds(transactionResolveDelay))); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java new file mode 100644 index 0000000000..4dda6996c8 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java @@ -0,0 +1,52 @@ +package org.apache.rocketmq.proxy.connector.transaction; + +import java.net.UnknownHostException; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TransactionIdTest { + + @Test + public void test() throws UnknownHostException { + TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + "71F99B78B6E261357FA259CCA6456118", 1234, 5678); + + TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); + + assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); + assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); + assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); + } + + @Test + public void testEmptyTransactionId() throws UnknownHostException { + TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + "", 1234, 5678); + + TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); + + assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); + assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); + assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); + } + + @Test + public void testNullTransactionId() throws UnknownHostException { + TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + null, 1234, 5678); + + TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); + + assertEquals("", decodeTransactionId.getBrokerTransactionId()); + assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); + assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); + } +} \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java index 271dc0b75c..bf5db915f5 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java @@ -17,6 +17,9 @@ package org.apache.rocketmq.test.base; +import apache.rocketmq.v1.Address; +import apache.rocketmq.v1.AddressScheme; +import apache.rocketmq.v1.Endpoints; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.QueryRouteRequest; @@ -94,10 +97,15 @@ public class GrpcBaseTest extends BaseConf { } public QueryRouteRequest buildQueryRouteRequest(String topic) { + return buildQueryRouteRequest(topic, Endpoints.getDefaultInstance()); + } + + public QueryRouteRequest buildQueryRouteRequest(String topic, Endpoints endpoints) { return QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) + .setEndpoints(endpoints) .build(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java new file mode 100644 index 0000000000..da098271bb --- /dev/null +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java @@ -0,0 +1,64 @@ +package org.apache.rocketmq.test.proxy; + +import apache.rocketmq.v1.Address; +import apache.rocketmq.v1.AddressScheme; +import apache.rocketmq.v1.Endpoints; +import apache.rocketmq.v1.MessagingServiceGrpc; +import apache.rocketmq.v1.QueryRouteResponse; +import io.grpc.Channel; +import java.net.URL; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; +import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; +import org.apache.rocketmq.test.base.GrpcBaseTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; + +public class ClusterGrpcTest extends GrpcBaseTest { + + private final int PORT = 8083; + private GrpcForwardService grpcForwardService; + private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + + @Before + public void setUp() throws Exception { + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); + ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + grpcForwardService = new ClusterGrpcService(); + grpcForwardService.start(); + GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); + Channel channel = setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + blockingStub = MessagingServiceGrpc.newBlockingStub(channel); + } + + @After + public void tearDown() throws Exception { + grpcForwardService.shutdown(); + shutdown(); + } + + @Test + public void testQueryRoute() { + String topic = initTopic(); + QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic, Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder() + .setHost("127.0.0.1") + .setPort(PORT) + .build()) + .build())); + assertQueryRoute(response, brokerControllerList.size()); + } +} From 04bdba44259698c4491b089a7e9d795de766b87b Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Mon, 21 Mar 2022 20:08:18 +0800 Subject: [PATCH 064/338] [ISSUE #3949] For passing check style. --- .../rocketmq/proxy/HealthCheckServer.java | 3 +- .../apache/rocketmq/proxy/ProxyStartup.java | 30 ++++++++++--------- .../proxy/grpc/adapter/InvocationContext.java | 6 ++-- .../adapter/channel/GrpcClientChannel.java | 10 +++++-- .../grpc/interceptor/HeaderInterceptor.java | 8 +++-- .../grpc/service/ClusterGrpcService.java | 5 ++-- .../proxy/grpc/service/LocalGrpcService.java | 25 +++++++++++----- .../grpc/service/cluster/ClientService.java | 1 - 8 files changed, 54 insertions(+), 34 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java index 789a0dcf29..d058dccb28 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -33,7 +33,8 @@ public class HealthCheckServer implements StartAndShutdown { @Override public void start() throws Exception { - this.healthChecker = HttpServer.create(new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0); + this.healthChecker = HttpServer.create( + new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0); this.healthChecker.createContext("/status", new HealthCheckHandler()); this.healthChecker.setExecutor(null); this.healthChecker.start(); 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 810fd8c1ed..6648992efc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -39,11 +39,12 @@ import org.slf4j.LoggerFactory; public class ProxyStartup { - private static final Logger log = LoggerFactory.getLogger(ProxyStartup.class); - private static final ProxyStartAndShutdown proxyStartAndShutdown = new ProxyStartAndShutdown(); + private static final Logger LOGGER = LoggerFactory.getLogger(ProxyStartup.class); + private static final ProxyStartAndShutdown PROXY_START_AND_SHUTDOWN = new ProxyStartAndShutdown(); private static class ProxyStartAndShutdown extends AbstractStartAndShutdown { - @Override public void appendStartAndShutdown(StartAndShutdown startAndShutdown) { + @Override + public void appendStartAndShutdown(StartAndShutdown startAndShutdown) { super.appendStartAndShutdown(startAndShutdown); } } @@ -59,30 +60,29 @@ public class ProxyStartup { // create and start grpcServer GrpcServer grpcServer = createGrpcServer(); - proxyStartAndShutdown.appendStartAndShutdown(grpcServer); + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); // health check server final HealthCheckServer healthCheckServer = new HealthCheckServer(); - proxyStartAndShutdown.appendStartAndShutdown(healthCheckServer); + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(healthCheckServer); Runtime.getRuntime().addShutdownHook(new Thread(() -> { - log.info("try to shutdown server"); - + LOGGER.info("try to shutdown server"); try { - proxyStartAndShutdown.shutdown(); + PROXY_START_AND_SHUTDOWN.shutdown(); } catch (Exception e) { - log.error("err when shutdown proxy", e); + LOGGER.error("err when shutdown proxy", e); } })); } catch (Exception e) { System.err.println("find a unexpect err." + e); e.printStackTrace(); - log.error("find a unexpect err.", e); + LOGGER.error("find a unexpect err.", e); System.exit(1); } System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); - log.info(new Date() + "rmq-proxy startup successfully"); + LOGGER.info(new Date() + "rmq-proxy startup successfully"); } private static GrpcServer createGrpcServer() throws Exception { @@ -93,15 +93,17 @@ public class ProxyStartup { } else if (ProxyMode.isLocalMode(proxyModeStr)) { BrokerController brokerController = createBrokerController(); StartAndShutdown brokerControllerWrapper = new StartAndShutdown() { - @Override public void start() throws Exception { + @Override + public void start() throws Exception { brokerController.start(); } - @Override public void shutdown() throws Exception { + @Override + public void shutdown() throws Exception { brokerController.shutdown(); } }; - proxyStartAndShutdown.appendStartAndShutdown(brokerControllerWrapper); + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(brokerControllerWrapper); grpcService = new LocalGrpcService(brokerController); } else { throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java index 8b0739efd3..bdf2ef601f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java @@ -21,9 +21,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class InvocationContext { - final private R request; - final private CompletableFuture response; - final private long timestamp = System.currentTimeMillis(); + private final R request; + private final CompletableFuture response; + private final long timestamp = System.currentTimeMillis(); public InvocationContext(R req, CompletableFuture resp) { request = req; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index 99ab1da516..65bd2ad5eb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -52,11 +52,17 @@ public class GrpcClientChannel extends SimpleChannel { this.pollCommandResponseFutureRef.set(future); } - public static GrpcClientChannel create(ChannelManager channelManager, String group, String clientId, PollCommandResponseManager manager) { + public static GrpcClientChannel create( + ChannelManager channelManager, + String group, + String clientId, + PollCommandResponseManager manager + ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), () -> new GrpcClientChannel(group, clientId, manager), - GrpcClientChannel.class); + GrpcClientChannel.class + ); channelManager.addGroupClientId(group, clientId); return channel; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java index d106f8f0d2..1cbb003610 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/HeaderInterceptor.java @@ -46,9 +46,11 @@ public class HeaderInterceptor implements ServerInterceptor { private String parseSocketAddress(SocketAddress socketAddress) { if (socketAddress instanceof InetSocketAddress) { InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; - return HostAndPort.fromParts(inetSocketAddress.getAddress() - .getHostAddress(), inetSocketAddress.getPort()) - .toString(); + return HostAndPort.fromParts( + inetSocketAddress.getAddress() + .getHostAddress(), + inetSocketAddress.getPort() + ).toString(); } return ""; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 889da0e2b4..1846efe19d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -181,8 +181,9 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return this.clientService.pollCommand(ctx, request); } - @Override public CompletableFuture reportThreadStackTrace(Context ctx, - ReportThreadStackTraceRequest request) { + @Override + public CompletableFuture reportThreadStackTrace(Context ctx, + ReportThreadStackTraceRequest request) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index ce4e7f78b1..d4c2cce67b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -136,7 +136,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.appendStartAndShutdown(new LocalGrpcServiceStartAndShutdown()); } - @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + @Override + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { return this.routeService.queryRoute(ctx, request); } @@ -257,7 +258,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + @Override + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); AckMessageRequestHeader requestHeader = Converter.buildAckMessageRequestHeader(request); @@ -282,7 +284,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { + @Override + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); @@ -364,7 +367,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { + @Override + public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { Partition partition = request.getPartition(); String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); int queueId = partition.getId(); @@ -386,7 +390,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .build()); } - @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { + @Override + public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { long timeRemaining = Context.current() .getDeadline() .timeRemaining(TimeUnit.MILLISECONDS); @@ -419,7 +424,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { + @Override + public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { String clientId = request.getClientId(); CompletableFuture future = new CompletableFuture<>(); switch (request.getGroupCase()) { @@ -479,6 +485,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, ReportMessageConsumptionResultRequest request) { + String commandId = request.getCommandId(); PollCommandResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); if (pollCommandResponseFuture != null) { @@ -497,7 +504,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .build()); } - @Override public CompletableFuture notifyClientTermination(Context ctx, + @Override + public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); @@ -512,7 +520,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return new CompletableFuture<>(); } - @Override public CompletableFuture changeInvisibleDuration(Context ctx, + @Override + public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java index 9872bd35c3..69aa281186 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java @@ -74,7 +74,6 @@ public class ClientService extends BaseService { if (request.hasProducerData()) { String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId, pollCommandResponseManager); - //TODO: Use the faked MQ Version ? ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); producerManager.registerProducer(producerGroup, clientChannelInfo); } From b8b753ba9721be0e7bfc5eefa7fae868c2a99e2e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 21 Mar 2022 20:13:10 +0800 Subject: [PATCH 065/338] [ISSUE #3949] Add Ack in LocalGrpcTest --- .../common/consumer/ReceiptHandle.java | 4 ++-- .../rocketmq/test/base/GrpcBaseTest.java | 22 +++++++++++++++++-- .../rocketmq/test/proxy/LocalGrpcTest.java | 4 ++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java index ee7f9a83bf..5b02418f44 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -25,8 +25,8 @@ import org.apache.rocketmq.common.message.MessageExt; public class ReceiptHandle { private static final String SEPARATOR = MessageConst.KEY_SEPARATOR; - private static final String NORMAL_TOPIC = "0"; - private static final String RETRY_TOPIC = "1"; + public static final String NORMAL_TOPIC = "0"; + public static final String RETRY_TOPIC = "1"; private final long startOffset; private final long retrieveTime; private final long invisibleTime; diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java index bf5db915f5..d46b76ff70 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.test.base; -import apache.rocketmq.v1.Address; -import apache.rocketmq.v1.AddressScheme; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; import apache.rocketmq.v1.Endpoints; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.Partition; @@ -145,6 +145,18 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public AckMessageRequest buildAckMessageRequest(String group, String topic, String receiptHandle) { + return AckMessageRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setReceiptHandle(receiptHandle) + .build(); + } + public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { assertThat(response.getCommon().getStatus().getCode()).isEqualTo(Code.OK_VALUE); assertThat(response.getPartitionsList().size()).isEqualTo(brokerSize * defaultQueueNums); @@ -167,4 +179,10 @@ public class GrpcBaseTest extends BaseConf { .getSystemAttribute() .getMessageId()).isEqualTo(messageId); } + + public void assertAck(AckMessageResponse response) { + assertThat(response.getCommon() + .getStatus() + .getCode()).isEqualTo(Code.OK_VALUE); + } } \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java index 16e3d54326..1295f0115c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.test.proxy; +import apache.rocketmq.v1.AckMessageResponse; import apache.rocketmq.v1.MessagingServiceGrpc; import apache.rocketmq.v1.QueryRouteResponse; import apache.rocketmq.v1.ReceiveMessageResponse; @@ -81,5 +82,8 @@ public class LocalGrpcTest extends GrpcBaseTest { ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); assertReceiveMessage(receiveResponse, messageId); + String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); + assertAck(ackMessageResponse); } } From 15d181cd70b66cd926bb2c946ee151d85831f166 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 22 Mar 2022 20:19:32 +0800 Subject: [PATCH 066/338] [ISSUE #3949] Support acl --- acl/pom.xml | 8 + .../apache/rocketmq/acl/AccessValidator.java | 11 +- .../acl/common/AuthorizationHeader.java | 137 ++++++++++ .../rocketmq/acl/common/MetadataHeader.java | 233 ++++++++++++++++++ .../acl/plain/PlainAccessValidator.java | 112 +++++++++ .../rocketmq/proxy/common/RequestMapping.java | 82 ++++++ .../rocketmq/proxy/config/ProxyConfig.java | 10 + .../rocketmq/proxy/grpc/GrpcServer.java | 20 +- .../AuthenticationInterceptor.java | 64 +++++ .../interceptor/InterceptorConstants.java | 3 + 10 files changed, 675 insertions(+), 5 deletions(-) create mode 100644 acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java create mode 100644 acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java diff --git a/acl/pom.xml b/acl/pom.xml index 686a398540..c80cc24b5c 100644 --- a/acl/pom.xml +++ b/acl/pom.xml @@ -19,6 +19,10 @@ rocketmq-acl ${project.version} + + ${project.groupId} + rocketmq-proto + ${project.groupId} rocketmq-remoting @@ -62,6 +66,10 @@ commons-validator commons-validator + + com.google.protobuf + protobuf-java-util + diff --git a/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java index 167fa26e88..8602525b36 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java @@ -17,9 +17,10 @@ package org.apache.rocketmq.acl; +import com.google.protobuf.GeneratedMessageV3; import java.util.List; import java.util.Map; - +import org.apache.rocketmq.acl.common.MetadataHeader; import org.apache.rocketmq.common.AclConfig; import org.apache.rocketmq.common.DataVersion; import org.apache.rocketmq.common.PlainAccessConfig; @@ -36,6 +37,14 @@ public interface AccessValidator { */ AccessResource parse(RemotingCommand request, String remoteAddr); + /** + * Parse to get the AccessResource from gRPC protocol + * @param messageV3 + * @param header + * @return Plain access resource + */ + AccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header); + /** * Validate the access resource. * diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java new file mode 100644 index 0000000000..5fd053a5f7 --- /dev/null +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.acl.common; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; + +public class AuthorizationHeader { + private static final String HEADER_SEPARATOR = " "; + private static final String CREDENTIALS_SEPARATOR = "/"; + private static final int AUTH_HEADER_KV_LENGTH = 2; + private static final int CREDENTIALS_LENGTH = 3; + private static final String CREDENTIAL = "Credential"; + private static final String SIGNED_HEADERS = "SignedHeaders"; + private static final String SIGNATURE = "Signature"; + private String method; + private String accessKey; + private String regionId; + private String channelKey; + private String[] signedHeaders; + private String signature; + + /** + * Parse authorization from gRPC header. + * + * @param header gRPC header string. + * @throws Exception exception. + */ + public AuthorizationHeader(String header) throws DecoderException { + String[] result = header.split(HEADER_SEPARATOR, 2); + if (result.length != 2) { + throw new DecoderException("authorization header is incorrect"); + } + this.method = result[0]; + String[] keyValues = result[1].split(","); + for (String keyValue : keyValues) { + String[] kv = keyValue.trim().split("=", 2); + int kvLength = kv.length; + if (kv.length != AUTH_HEADER_KV_LENGTH) { + throw new DecoderException("authorization keyValues length is incorrect, actual length=" + kvLength); + } + String authItem = kv[0]; + if (CREDENTIAL.equals(authItem)) { + String[] credential = kv[1].split(CREDENTIALS_SEPARATOR); + int credentialActualLength = credential.length; + if (credentialActualLength < CREDENTIALS_LENGTH) { + throw new DecoderException("authorization credential length is incorrect, actual length=" + credentialActualLength); + } + this.accessKey = credential[0]; + this.regionId = credential[1]; + this.channelKey = credential[2]; + continue; + } + if (SIGNED_HEADERS.equals(authItem)) { + this.signedHeaders = kv[1].split(";"); + continue; + } + if (SIGNATURE.equals(authItem)) { + this.signature = this.hexToBase64(kv[1]); + } + } + } + + public String hexToBase64(String input) throws DecoderException { + byte[] bytes = Hex.decodeHex(input); + return Base64.encodeBase64String(bytes); + } + + public String getMethod() { + return this.method; + } + + public String getAccessKey() { + return this.accessKey; + } + + public String getRegionId() { + return this.regionId; + } + + public String getChannelKey() { + return this.channelKey; + } + + public String[] getSignedHeaders() { + return this.signedHeaders; + } + + public String getSignature() { + return this.signature; + } + + public void setMethod(final String method) { + this.method = method; + } + + public void setAccessKey(final String accessKey) { + this.accessKey = accessKey; + } + + public void setRegionId(final String regionId) { + this.regionId = regionId; + } + + public void setChannelKey(final String channelKey) { + this.channelKey = channelKey; + } + + public void setSignedHeaders(final String[] signedHeaders) { + this.signedHeaders = signedHeaders; + } + + public void setSignature(final String signature) { + this.signature = signature; + } + + @java.lang.Override + public java.lang.String toString() { + return "GrpcAuthHeader(method=" + this.getMethod() + ", accessKey=" + this.getAccessKey() + ", regionId=" + this.getRegionId() + ", channelKey=" + this.getChannelKey() + ", signedHeaders=" + java.util.Arrays.deepToString(this.getSignedHeaders()) + ", signature=" + this.getSignature() + ")"; + } +} diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java new file mode 100644 index 0000000000..a6824918a3 --- /dev/null +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.acl.common; + +public class MetadataHeader { + private String remoteAddress; + private String tenantId; + private String namespace; + private String authorization; + private String datetime; + private String sessionToken; + private String requestId; + private String language; + private String clientVersion; + private String protocol; + private int requestCode; + + MetadataHeader(final String remoteAddress, final String tenantId, final String namespace, + final String authorization, final String datetime, final String sessionToken, final String requestId, + final String language, final String clientVersion, final String protocol, final int requestCode) { + this.remoteAddress = remoteAddress; + this.tenantId = tenantId; + this.namespace = namespace; + this.authorization = authorization; + this.datetime = datetime; + this.sessionToken = sessionToken; + this.requestId = requestId; + this.language = language; + this.clientVersion = clientVersion; + this.protocol = protocol; + this.requestCode = requestCode; + } + + public static class MetadataHeaderBuilder { + private String remoteAddress; + private String tenantId; + private String namespace; + private String authorization; + private String datetime; + private String sessionToken; + private String requestId; + private String language; + private String clientVersion; + private String protocol; + private int requestCode; + + MetadataHeaderBuilder() { + } + + public MetadataHeader.MetadataHeaderBuilder remoteAddress(final String remoteAddress) { + this.remoteAddress = remoteAddress; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder tenantId(final String tenantId) { + this.tenantId = tenantId; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder namespace(final String namespace) { + this.namespace = namespace; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder authorization(final String authorization) { + this.authorization = authorization; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder datetime(final String datetime) { + this.datetime = datetime; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder sessionToken(final String sessionToken) { + this.sessionToken = sessionToken; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder requestId(final String requestId) { + this.requestId = requestId; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder language(final String language) { + this.language = language; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder clientVersion(final String clientVersion) { + this.clientVersion = clientVersion; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder protocol(final String protocol) { + this.protocol = protocol; + return this; + } + + public MetadataHeader.MetadataHeaderBuilder requestCode(final int requestCode) { + this.requestCode = requestCode; + return this; + } + + public MetadataHeader build() { + return new MetadataHeader(this.remoteAddress, this.tenantId, this.namespace, this.authorization, + this.datetime, this.sessionToken, this.requestId, this.language, this.clientVersion, this.protocol, + this.requestCode); + } + + @Override public String toString() { + return "MetadataHeaderBuilder{" + "remoteAddress='" + remoteAddress + '\'' + + ", tenantId='" + tenantId + '\'' + + ", namespace='" + namespace + '\'' + + ", authorization='" + authorization + '\'' + + ", datetime='" + datetime + '\'' + + ", sessionToken='" + sessionToken + '\'' + + ", requestId='" + requestId + '\'' + + ", language='" + language + '\'' + + ", clientVersion='" + clientVersion + '\'' + + ", protocol='" + protocol + '\'' + + ", requestCode=" + requestCode + + '}'; + } + } + + public static MetadataHeader.MetadataHeaderBuilder builder() { + return new MetadataHeader.MetadataHeaderBuilder(); + } + + public String getRemoteAddress() { + return this.remoteAddress; + } + + public String getTenantId() { + return this.tenantId; + } + + public String getNamespace() { + return this.namespace; + } + + public String getAuthorization() { + return this.authorization; + } + + public String getDatetime() { + return this.datetime; + } + + public String getSessionToken() { + return this.sessionToken; + } + + public String getRequestId() { + return this.requestId; + } + + public String getLanguage() { + return this.language; + } + + public String getClientVersion() { + return this.clientVersion; + } + + public String getProtocol() { + return this.protocol; + } + + public int getRequestCode() { + return this.requestCode; + } + + public void setRemoteAddress(final String remoteAddress) { + this.remoteAddress = remoteAddress; + } + + public void setTenantId(final String tenantId) { + this.tenantId = tenantId; + } + + public void setNamespace(final String namespace) { + this.namespace = namespace; + } + + public void setAuthorization(final String authorization) { + this.authorization = authorization; + } + + public void setDatetime(final String datetime) { + this.datetime = datetime; + } + + public void setSessionToken(final String sessionToken) { + this.sessionToken = sessionToken; + } + + public void setRequestId(final String requestId) { + this.requestId = requestId; + } + + public void setLanguage(final String language) { + this.language = language; + } + + public void setClientVersion(final String clientVersion) { + this.clientVersion = clientVersion; + } + + public void setProtocol(final String protocol) { + this.protocol = protocol; + } + + public void setRequestCode(int requestCode) { + this.requestCode = requestCode; + } +} diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index 83f43ef7eb..6e1f78463e 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -16,20 +16,36 @@ */ package org.apache.rocketmq.acl.plain; +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SendMessageRequest; +import com.google.protobuf.GeneratedMessageV3; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; +import org.apache.commons.codec.DecoderException; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.AclUtils; +import org.apache.rocketmq.acl.common.AuthorizationHeader; +import org.apache.rocketmq.acl.common.MetadataHeader; import org.apache.rocketmq.acl.common.Permission; import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.common.AclConfig; import org.apache.rocketmq.common.DataVersion; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.PlainAccessConfig; +import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; @@ -136,6 +152,102 @@ public class PlainAccessValidator implements AccessValidator { return accessResource; } + @Override public AccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header) { + PlainAccessResource accessResource = new PlainAccessResource(); + String remoteAddress = header.getRemoteAddress(); + if (remoteAddress != null && remoteAddress.contains(":")) { + accessResource.setWhiteRemoteAddress(remoteAddress.substring(0, remoteAddress.lastIndexOf(':'))); + } else { + accessResource.setWhiteRemoteAddress(remoteAddress); + } + try { + AuthorizationHeader authorizationHeader = new AuthorizationHeader(header.getAuthorization()); + accessResource.setAccessKey(authorizationHeader.getAccessKey()); + accessResource.setSignature(authorizationHeader.getSignature()); + } catch (DecoderException e) { + throw new AclException(e.getMessage(), e); + } + accessResource.setSecretToken(header.getSessionToken()); + accessResource.setRequestCode(header.getRequestCode()); + accessResource.setContent(header.getDatetime().getBytes(StandardCharsets.UTF_8)); + + try { + String rpcFullName = messageV3.getDescriptorForType().getFullName(); + if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { + HeartbeatRequest request = (HeartbeatRequest) messageV3; + if (request.hasProducerData()) { + Resource group = request.getProducerData() + .getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + } else if (request.hasConsumerData()) { + Resource group = request.getConsumerData() + .getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + } + } else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + SendMessageRequest request = (SendMessageRequest) messageV3; + Resource topic = request.getMessage().getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.PUB); + } else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + ReceiveMessageRequest request = (ReceiveMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getPartition().getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + AckMessageRequest request = (AckMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (NackMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + NackMessageRequest request = (NackMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) { + ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { + EndTransactionRequest request = (EndTransactionRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.PUB); + } else if (QueryOffsetRequest.getDescriptor().getFullName().equals(rpcFullName)) { + QueryOffsetRequest request = (QueryOffsetRequest) messageV3; + Resource topic = request.getPartition().getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (PullMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + PullMessageRequest request = (PullMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getPartition().getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } + } catch (Throwable t) { + throw new AclException(t.getMessage(), t); + } + return accessResource; + } + @Override public void validate(AccessResource accessResource) { aclPlugEngine.validate((PlainAccessResource) accessResource); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java new file mode 100644 index 0000000000..7a2ae4dd22 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java @@ -0,0 +1,82 @@ +/* + * 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.common; + +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.ChangeInvisibleDurationRequest; +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v1.HealthCheckRequest; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryRouteRequest; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.SendMessageRequest; +import org.apache.rocketmq.common.protocol.RequestCode; + +public class RequestMapping { + public static int map(String rpcFullName) { + if (QueryRouteRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.GET_ROUTEINFO_BY_TOPIC; + } + if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.HEART_BEAT; + } + if (HealthCheckRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.HEART_BEAT; + } + if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.SEND_MESSAGE_V2; + } + if (QueryAssignmentRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.GET_ROUTEINFO_BY_TOPIC; + } + if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.PULL_MESSAGE; + } + if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.UPDATE_CONSUMER_OFFSET; + } + if (NackMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.CONSUMER_SEND_MSG_BACK; + } + if (ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.CONSUMER_SEND_MSG_BACK; + } + if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.END_TRANSACTION; + } + if (QueryOffsetRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.SEARCH_OFFSET_BY_TIMESTAMP; + } + if (PullMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.PULL_MESSAGE; + } + if (NotifyClientTerminationRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.UNREGISTER_CLIENT; + } + if (ChangeInvisibleDurationRequest.getDescriptor().getFullName().equals(rpcFullName)) { + return RequestCode.CONSUMER_SEND_MSG_BACK; + } + return RequestCode.HEART_BEAT; + } +} 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 cb23d66c6b..494bf75177 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 @@ -82,6 +82,8 @@ public class ProxyConfig { private int retryDelayLevelDelta = 3; private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; + private boolean enableACL = false; + public Integer getHealthCheckPort() { return healthCheckPort; } @@ -385,4 +387,12 @@ public class ProxyConfig { public void setMessageDelayLevel(String messageDelayLevel) { this.messageDelayLevel = messageDelayLevel; } + + public boolean isEnableACL() { + return enableACL; + } + + public void setEnableACL(boolean enableACL) { + this.enableACL = enableACL; + } } 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 c5e318a245..dc36a5e13f 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 @@ -27,12 +27,16 @@ import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactor import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.acl.AccessValidator; +import org.apache.rocketmq.broker.util.ServiceProvider; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; @@ -86,14 +90,22 @@ public class GrpcServer implements StartAndShutdown { int workerLoopNum = ConfigurationManager.getProxyConfig().getGrpcWorkerLoopNum(); int maxInboundMessageSize = ConfigurationManager.getProxyConfig().getGrpcMaxInboundMessageSize(); - this.server = serverBuilder - .maxInboundMessageSize(maxInboundMessageSize) + serverBuilder.maxInboundMessageSize(maxInboundMessageSize) .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) .channelType(NioServerSocketChannel.class) .addService(messagingProcessor) - .executor(this.executor) - .intercept(new ContextInterceptor()) + .executor(this.executor); + + if (ConfigurationManager.getProxyConfig().isEnableACL()) { + List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); + if (accessValidators.isEmpty()) { + throw new IllegalArgumentException("Load AccessValidator failed"); + } + serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); + } + + this.server = serverBuilder.intercept(new ContextInterceptor()) .intercept(new HeaderInterceptor()) .build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java new file mode 100644 index 0000000000..f691399c85 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -0,0 +1,64 @@ +/* + * 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.grpc.interceptor; + +import com.google.protobuf.GeneratedMessageV3; +import io.grpc.Context; +import io.grpc.ForwardingServerCallListener; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import java.util.List; +import org.apache.rocketmq.acl.AccessValidator; +import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.proxy.common.RequestMapping; + +public class AuthenticationInterceptor implements ServerInterceptor { + private final List accessValidatorList; + + public AuthenticationInterceptor(List accessValidatorList) { + this.accessValidatorList = accessValidatorList; + } + + @Override + public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, + ServerCallHandler next) { + return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { + @Override + public void onMessage(ReqT message) { + GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; + MetadataHeader metadataHeader = MetadataHeader.builder() + .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) + .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) + .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) + .datetime(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.DATE_TIME)) + .sessionToken(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.SESSION_TOKEN)) + .requestId(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REQUEST_ID)) + .language(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE)) + .clientVersion(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.CLIENT_VERSION)) + .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) + .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) + .build(); + for (AccessValidator accessValidator : accessValidatorList) { + accessValidator.validate(accessValidator.parse(messageV3, metadataHeader)); + } + } + }; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index 5a672f43ea..73578a39d7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -62,4 +62,7 @@ public class InterceptorConstants { public static final Metadata.Key RPC_NAME = Metadata.Key.of("x-mq-rpc-name", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key SESSION_TOKEN + = Metadata.Key.of("x-mq-session-token", Metadata.ASCII_STRING_MARSHALLER); } From 76cf9dbdc18cb65eaa01be74a96cb1a0673b4764 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 23 Mar 2022 11:40:35 +0800 Subject: [PATCH 067/338] [ISSUE #3949] For passing check style. --- ...entAPIExtImpl.java => MQClientAPIExt.java} | 125 +++++++++++------- .../connector/AbstractForwardClient.java | 13 +- .../proxy/connector/DefaultForwardClient.java | 4 +- .../proxy/connector/ForwardProducer.java | 4 +- .../proxy/connector/ForwardReadConsumer.java | 4 +- .../proxy/connector/ForwardWriteConsumer.java | 4 +- .../factory/AbstractMQClientFactory.java | 16 +-- .../factory/ForwardClientFactory.java | 6 +- .../AuthenticationInterceptor.java | 8 +- .../grpc/service/ClusterGrpcService.java | 9 +- 10 files changed, 115 insertions(+), 78 deletions(-) rename client/src/main/java/org/apache/rocketmq/client/impl/{MQClientAPIExtImpl.java => MQClientAPIExt.java} (85%) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java similarity index 85% rename from client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java rename to client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java index a9474fd37e..c440cd6c0b 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExtImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java @@ -57,16 +57,18 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MQClientAPIExtImpl { +public class MQClientAPIExt { + private static final Logger LOGGER = LoggerFactory.getLogger(MQClientAPIExt.class); - private static final Logger log = LoggerFactory.getLogger(MQClientAPIExtImpl.class); - - private final MQClientAPIImpl mqClientAPI; private final ClientConfig clientConfig; + private final MQClientAPIImpl mqClientAPI; - public MQClientAPIExtImpl(NettyClientConfig nettyClientConfig, + public MQClientAPIExt( + ClientConfig clientConfig, + NettyClientConfig nettyClientConfig, ClientRemotingProcessor clientRemotingProcessor, - RPCHook rpcHook, ClientConfig clientConfig) { + RPCHook rpcHook + ) { this.clientConfig = clientConfig; this.mqClientAPI = new MQClientAPIImpl(nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig); } @@ -86,7 +88,7 @@ public class MQClientAPIExtImpl { public boolean updateNameServerAddressList() { if (this.clientConfig.getNamesrvAddr() != null) { this.mqClientAPI.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); - log.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); + LOGGER.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); return true; } return false; @@ -109,8 +111,11 @@ public class MQClientAPIExtImpl { return this.mqClientAPI.getRemotingClient(); } - public CompletableFuture sendHeartbeat(String brokerAddr, HeartbeatData heartbeatData, - long timeoutMillis) { + public CompletableFuture sendHeartbeat( + String brokerAddr, + HeartbeatData heartbeatData, + long timeoutMillis + ) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); request.setLanguage(clientConfig.getLanguage()); request.setBody(heartbeatData.encode()); @@ -140,9 +145,13 @@ public class MQClientAPIExtImpl { this.mqClientAPI.endTransactionOneway(brokerAddr, requestHeader, remark, timeoutMillis); } - public CompletableFuture sendMessage(String brokerAddr, String brokerName, Message msg, - SendMessageRequestHeader requestHeader, long timeoutMillis) { - + public CompletableFuture sendMessage( + String brokerAddr, + String brokerName, + Message msg, + SendMessageRequestHeader requestHeader, + long timeoutMillis + ) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); request.setBody(msg.getBody()); @@ -166,9 +175,11 @@ public class MQClientAPIExtImpl { return future; } - public CompletableFuture sendMessageBack(String brokerAddr, + public CompletableFuture sendMessageBack( + String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, - long timeoutMillis) { + long timeoutMillis + ) { CompletableFuture future = new CompletableFuture<>(); try { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); @@ -186,9 +197,12 @@ public class MQClientAPIExtImpl { return future; } - public CompletableFuture popMessage(String brokerAddr, String brokerName, + public CompletableFuture popMessage( + String brokerAddr, + String brokerName, PopMessageRequestHeader requestHeader, - long timeoutMillis) { + long timeoutMillis + ) { CompletableFuture future = new CompletableFuture<>(); try { this.mqClientAPI.popMessageAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new PopCallback() { @@ -208,8 +222,11 @@ public class MQClientAPIExtImpl { return future; } - public CompletableFuture ackMessage(String brokerAddr, AckMessageRequestHeader requestHeader, - long timeoutMillis) { + public CompletableFuture ackMessage( + String brokerAddr, + AckMessageRequestHeader requestHeader, + long timeoutMillis + ) { CompletableFuture future = new CompletableFuture<>(); try { this.mqClientAPI.ackMessageAsync(brokerAddr, timeoutMillis, new AckCallback() { @@ -229,56 +246,73 @@ public class MQClientAPIExtImpl { return future; } - public CompletableFuture changeInvisibleTimeAsync(String brokerAddr, String brokerName, - ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture changeInvisibleTimeAsync( + String brokerAddr, + String brokerName, + ChangeInvisibleTimeRequestHeader requestHeader, + long timeoutMillis + ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new AckCallback() { - @Override - public void onSuccess(AckResult ackResult) { - future.complete(ackResult); - } + this.mqClientAPI.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, + new AckCallback() { + @Override + public void onSuccess(AckResult ackResult) { + future.complete(ackResult); + } - @Override - public void onException(Throwable t) { - future.completeExceptionally(t); + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } } - }); + ); } catch (Throwable t) { future.completeExceptionally(t); } return future; } - public CompletableFuture pullMessage(String brokerAddr, PullMessageRequestHeader requestHeader, - long timeoutMillis) { + public CompletableFuture pullMessage( + String brokerAddr, + PullMessageRequestHeader requestHeader, + long timeoutMillis + ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.pullMessage(brokerAddr, requestHeader, timeoutMillis, CommunicationMode.ASYNC, new PullCallback() { - @Override - public void onSuccess(PullResult pullResult) { - future.complete(pullResult); - } + this.mqClientAPI.pullMessage(brokerAddr, requestHeader, timeoutMillis, CommunicationMode.ASYNC, + new PullCallback() { + @Override + public void onSuccess(PullResult pullResult) { + future.complete(pullResult); + } - @Override - public void onException(Throwable t) { - future.completeExceptionally(t); + @Override + public void onException(Throwable t) { + future.completeExceptionally(t); + } } - }); + ); } catch (Throwable t) { future.completeExceptionally(t); } return future; } - public void updateConsumerOffsetOneWay(String brokerAddr, UpdateConsumerOffsetRequestHeader header, - long timeoutMillis) throws InterruptedException, RemotingException { + public void updateConsumerOffsetOneWay( + String brokerAddr, + UpdateConsumerOffsetRequestHeader header, + long timeoutMillis + ) throws InterruptedException, RemotingException { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONSUMER_OFFSET, header); this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); } - public CompletableFuture> getConsumerListByGroup(String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, - long timeoutMillis) { + public CompletableFuture> getConsumerListByGroup( + String brokerAddr, + GetConsumerListByGroupRequestHeader requestHeader, + long timeoutMillis + ) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_LIST_BY_GROUP, requestHeader); CompletableFuture> future = new CompletableFuture<>(); @@ -317,7 +351,8 @@ public class MQClientAPIExtImpl { return future; } - public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { + public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) + throws RemotingException, InterruptedException, MQClientException { return this.mqClientAPI.getTopicRouteInfoFromNameServer(topic, timeoutMillis); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 0fa3c3746b..2f08e7e67c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -17,14 +17,14 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.ThreadLocalRandom; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; public abstract class AbstractForwardClient implements StartAndShutdown { private final ForwardClientFactory forwardClientFactory; - private MQClientAPIExtImpl[] clients; + private MQClientAPIExt[] clients; public AbstractForwardClient(ForwardClientFactory forwardClientFactory) { this.forwardClientFactory = forwardClientFactory; @@ -32,11 +32,11 @@ public abstract class AbstractForwardClient implements StartAndShutdown { protected abstract int getClientNum(); - protected abstract MQClientAPIExtImpl createNewClient(ForwardClientFactory forwardClientFactory, String name); + protected abstract MQClientAPIExt createNewClient(ForwardClientFactory forwardClientFactory, String name); protected abstract String getNamePrefix(); - protected MQClientAPIExtImpl getClient() { + protected MQClientAPIExt getClient() { if (clients.length == 1) { return this.clients[0]; } @@ -46,7 +46,8 @@ public abstract class AbstractForwardClient implements StartAndShutdown { @Override public void start() throws Exception { int clientCount = getClientNum(); - this.clients = new MQClientAPIExtImpl[clientCount]; + this.clients = new MQClientAPIExt[clientCount]; + for (int i = 0; i < clientCount; i++) { String name = getNamePrefix() + "N_" + i; clients[i] = createNewClient(forwardClientFactory, name); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index b1e032c2f4..81d180e66e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -39,7 +39,7 @@ public class DefaultForwardClient extends AbstractForwardClient { } @Override - protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getDefaultForwardClientWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 8facf9a8e4..2f6d504c72 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.Message; @@ -46,7 +46,7 @@ public class ForwardProducer extends AbstractForwardClient { } @Override - protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { double sendClientWorkerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * sendClientWorkerFactor); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 0aa0b30d70..a8faa303b3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; @@ -39,7 +39,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { } @Override - protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 5d3f5c2035..fc67796796 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -18,7 +18,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; @@ -40,7 +40,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { } @Override - protected MQClientAPIExtImpl createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java index c7417d4d46..6f126e9200 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java @@ -20,10 +20,10 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.ClientRemotingProcessor; -import org.apache.rocketmq.client.impl.MQClientAPIExtImpl; +import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.remoting.RPCHook; -public abstract class AbstractMQClientFactory extends AbstractClientFactory { +public abstract class AbstractMQClientFactory extends AbstractClientFactory { public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { @@ -33,20 +33,20 @@ public abstract class AbstractMQClientFactory extends AbstractClientFactory ServerCall.Listener interceptCall(ServerCall call, Metadata headers, - ServerCallHandler next) { - return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { + public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, + ServerCallHandler next) { + return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { @Override - public void onMessage(ReqT message) { + public void onMessage(R message) { GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; MetadataHeader metadataHeader = MetadataHeader.builder() .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 1846efe19d..63bee24262 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -124,10 +124,11 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { - final HealthCheckResponse response = HealthCheckResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build(); - return CompletableFuture.completedFuture(response); + return CompletableFuture.completedFuture( + HealthCheckResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .build() + ); } @Override From 36b1e9fa2aac47af5972740f894ed92e4d0715ef Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 25 Mar 2022 12:44:02 +0800 Subject: [PATCH 068/338] [ISSUE #3949] Move common package, using adapter. --- .../apache/rocketmq/proxy/ProxyStartup.java | 2 +- .../rocketmq/proxy/config/Configuration.java | 10 ++- .../rocketmq/proxy/config/ProxyConfig.java | 2 +- .../connector/AbstractForwardClient.java | 14 ++-- .../proxy/connector/DefaultForwardClient.java | 19 ++---- .../proxy/connector/ForwardProducer.java | 19 +++--- .../proxy/connector/ForwardReadConsumer.java | 7 +- .../proxy/connector/ForwardWriteConsumer.java | 7 +- .../factory/AbstractClientFactory.java | 2 +- .../factory/AbstractMQClientFactory.java | 8 +-- .../proxy/grpc/GrpcMessagingProcessor.java | 2 +- .../grpc/{common => adapter}/DelayPolicy.java | 2 +- .../GrpcConverter.java} | 64 +++++++++---------- .../ParameterConverter.java | 2 +- .../PollResponseFuture.java} | 8 +-- .../PollResponseManager.java} | 10 +-- .../{common => adapter}/ProxyException.java | 2 +- .../grpc/{common => adapter}/ProxyMode.java | 2 +- .../ProxyResponseCode.java | 2 +- .../{common => adapter}/ResponseBuilder.java | 2 +- .../{common => adapter}/ResponseHook.java | 2 +- .../{common => adapter}/ResponseWriter.java | 2 +- .../adapter/channel/GrpcClientChannel.java | 14 ++-- .../handler/PullMessageResponseHandler.java | 9 +-- .../ReceiveMessageResponseHandler.java | 8 +-- .../handler/SendMessageResponseHandler.java | 2 +- .../grpc/service/ClusterGrpcService.java | 16 ++--- .../proxy/grpc/service/LocalGrpcService.java | 52 +++++++-------- .../grpc/service/cluster/BaseService.java | 2 +- .../grpc/service/cluster/ConsumerService.java | 26 ++++---- .../DefaultAssignmentQueueSelector.java | 4 +- ...Service.java => ForwardClientService.java} | 56 +++++++++------- .../grpc/service/cluster/ProducerService.java | 16 ++--- .../service/cluster/PullMessageService.java | 20 +++--- .../grpc/service/cluster/RouteService.java | 14 ++-- .../service/cluster/TransactionService.java | 10 +-- .../proxy/common/utils/FilterUtilTest.java | 9 ++- .../config/ConfigurationManagerTest.java | 2 +- .../connector/ForwardClientManagerTest.java | 22 ++++--- .../grpc/service/LocalGrpcServiceTest.java | 6 +- .../DefaultProducerQueueSelectorTest.java | 18 +++--- .../service/cluster/ProducerServiceTest.java | 2 +- .../service/cluster/RouteServiceTest.java | 2 +- 43 files changed, 252 insertions(+), 248 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/DelayPolicy.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common/Converter.java => adapter/GrpcConverter.java} (92%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ParameterConverter.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common/PollCommandResponseFuture.java => adapter/PollResponseFuture.java} (84%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common/PollCommandResponseManager.java => adapter/PollResponseManager.java} (77%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ProxyException.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ProxyMode.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ProxyResponseCode.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ResponseBuilder.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ResponseHook.java (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{common => adapter}/ResponseWriter.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ClientService.java => ForwardClientService.java} (75%) 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 6648992efc..27a21eb626 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -30,7 +30,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java index 84a41a3c9f..9e79532e32 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java @@ -25,11 +25,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Configuration { - private final static Logger log = LoggerFactory.getLogger(Configuration.class); + private final static Logger LOGGER = LoggerFactory.getLogger(Configuration.class); private final AtomicReference proxyConfigReference = new AtomicReference<>(); public void init() throws Exception { String proxyConfigData = loadJsonConfig(ProxyConfig.CONFIG_FILE_NAME); + if (null == proxyConfigData) { + throw new RuntimeException(String.format("load configuration from file: %s error.", ProxyConfig.CONFIG_FILE_NAME)); + } + ProxyConfig proxyConfig = JSON.parseObject(proxyConfigData, ProxyConfig.class); setProxyConfig(proxyConfig); } @@ -39,12 +43,12 @@ public class Configuration { File file = new File(filePath); if (!file.exists()) { - log.warn("the config file {} not exist", filePath); + LOGGER.warn("the config file {} not exist", filePath); return null; } long fileLength = file.length(); if (fileLength <= 0) { - log.warn("the config file {} length is zero", filePath); + LOGGER.warn("the config file {} length is zero", filePath); return null; } 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 494bf75177..9c09b8bb33 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 @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 2f08e7e67c..1ea6539a92 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -23,18 +23,22 @@ import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; public abstract class AbstractForwardClient implements StartAndShutdown { - private final ForwardClientFactory forwardClientFactory; + private final ForwardClientFactory clientFactory; private MQClientAPIExt[] clients; + private final String gidPrefix; - public AbstractForwardClient(ForwardClientFactory forwardClientFactory) { - this.forwardClientFactory = forwardClientFactory; + public AbstractForwardClient(ForwardClientFactory clientFactory, String gidPrefix) { + this.clientFactory = clientFactory; + this.gidPrefix = gidPrefix; } protected abstract int getClientNum(); protected abstract MQClientAPIExt createNewClient(ForwardClientFactory forwardClientFactory, String name); - protected abstract String getNamePrefix(); + protected String getNamePrefix() { + return this.gidPrefix; + } protected MQClientAPIExt getClient() { if (clients.length == 1) { @@ -50,7 +54,7 @@ public abstract class AbstractForwardClient implements StartAndShutdown { for (int i = 0; i < clientCount; i++) { String name = getNamePrefix() + "N_" + i; - clients[i] = createNewClient(forwardClientFactory, name); + clients[i] = createNewClient(clientFactory, name); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 81d180e66e..43d7bbafd9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -29,8 +29,8 @@ import org.apache.rocketmq.remoting.exception.RemotingException; public class DefaultForwardClient extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; - public DefaultForwardClient(ForwardClientFactory forwardClientFactory) { - super(forwardClientFactory); + public DefaultForwardClient(ForwardClientFactory clientFactory) { + super(clientFactory, CID_PREFIX); } @Override @@ -41,27 +41,22 @@ public class DefaultForwardClient extends AbstractForwardClient { @Override protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getDefaultForwardClientWorkerFactor(); - final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); + int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getMQClient(name, threadCount); } - @Override - protected String getNamePrefix() { - return CID_PREFIX; - } - public CompletableFuture> getConsumerListByGroup( String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis ) { - return getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); + return this.getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); } public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { - return getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); + return this.getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } public CompletableFuture getMaxOffset( @@ -70,7 +65,7 @@ public class DefaultForwardClient extends AbstractForwardClient { int queueId, long timeoutMillis ) { - return getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); + return this.getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); } public CompletableFuture searchOffset( @@ -80,6 +75,6 @@ public class DefaultForwardClient extends AbstractForwardClient { long timestamp, long timeoutMillis ) { - return getClient().searchOffset(brokerAddr, topic, queueId, timestamp, timeoutMillis); + return this.getClient().searchOffset(brokerAddr, topic, queueId, timestamp, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 2f6d504c72..835c8dbbd2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -37,7 +37,7 @@ public class ForwardProducer extends AbstractForwardClient { private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; public ForwardProducer(ForwardClientFactory clientFactory) { - super(clientFactory); + super(clientFactory, PID_PREFIX); } @Override @@ -47,16 +47,12 @@ public class ForwardProducer extends AbstractForwardClient { @Override protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { - double sendClientWorkerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); - final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * sendClientWorkerFactor); + double workerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); + final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getTransactionalProducer(name, threadCount); } - @Override - protected String getNamePrefix() { - return PID_PREFIX; - } public CompletableFuture heartBeat(String heartbeatAddr, HeartbeatData heartbeatData, long timeout) throws Exception { return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); @@ -83,8 +79,13 @@ public class ForwardProducer extends AbstractForwardClient { ); } - public CompletableFuture sendMessage(String address, String brokerName, Message msg, - SendMessageRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture sendMessage( + String address, + String brokerName, + Message msg, + SendMessageRequestHeader requestHeader, + long timeoutMillis + ) { CompletableFuture future = this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); return future.thenApply(sendResult -> { int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index a8faa303b3..869aeffc14 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -30,7 +30,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_CONSUME_MESSAGE_"; public ForwardReadConsumer(ForwardClientFactory clientFactory) { - super(clientFactory); + super(clientFactory, CID_PREFIX); } @Override @@ -46,11 +46,6 @@ public class ForwardReadConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - @Override - protected String getNamePrefix() { - return CID_PREFIX; - } - public CompletableFuture popMessage(String address, String brokerName, PopMessageRequestHeader requestHeader, long timeoutMillis) { return getClient().popMessage(address, brokerName, requestHeader, timeoutMillis); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index fc67796796..1c0d721cc0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -31,7 +31,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DELETE_MESSAGE_"; public ForwardWriteConsumer(ForwardClientFactory clientFactory) { - super(clientFactory); + super(clientFactory, CID_PREFIX); } @Override @@ -47,11 +47,6 @@ public class ForwardWriteConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - @Override - protected String getNamePrefix() { - return CID_PREFIX; - } - public CompletableFuture ackMessage( String address, AckMessageRequestHeader requestHeader, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java index daae5bc2bd..f5d3aa379a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java @@ -78,7 +78,7 @@ public abstract class AbstractClientFactory { try { this.shutdown(v); } catch (Exception e) { - LOGGER.warn("RocketMQClientConstructor shutdown all err.", e); + LOGGER.warn("try to shutdown client err.", e); } }); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java index 6f126e9200..1a772dc04d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector.factory; +import java.time.Duration; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.ClientConfig; @@ -25,8 +26,7 @@ import org.apache.rocketmq.remoting.RPCHook; public abstract class AbstractMQClientFactory extends AbstractClientFactory { - public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, - RPCHook rpcHook) { + public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { super(scheduledExecutorService, rpcHook); } @@ -50,8 +50,8 @@ public abstract class AbstractMQClientFactory extends AbstractClientFactory property = buildMessageProperty(message); - requestHeader.setProducerGroup(getResourceNameWithNamespace(systemAttribute.getProducerGroup())); - requestHeader.setTopic(getResourceNameWithNamespace(message.getTopic())); + requestHeader.setProducerGroup(wrapResourceWithNamespace(systemAttribute.getProducerGroup())); + requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); requestHeader.setDefaultTopic(""); requestHeader.setDefaultTopicQueueNums(0); requestHeader.setQueueId(systemAttribute.getPartitionId()); @@ -135,10 +135,10 @@ public class Converter { public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { Resource group = request.getGroup(); - String groupName = Converter.getResourceNameWithNamespace(group); + String groupName = GrpcConverter.wrapResourceWithNamespace(group); Partition partition = request.getPartition(); Resource topic = partition.getTopic(); - String topicName = Converter.getResourceNameWithNamespace(topic); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); int queueId = partition.getId(); int maxMessageNumbers = request.getBatchSize(); if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { @@ -149,11 +149,11 @@ public class Converter { long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); ConsumePolicy policy = request.getConsumePolicy(); - int initMode = Converter.buildConsumeInitMode(policy); + int initMode = GrpcConverter.buildConsumeInitMode(policy); FilterExpression filterExpression = request.getFilterExpression(); String expression = filterExpression.getExpression(); - String expressionType = Converter.buildExpressionType(filterExpression.getType()); + String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); requestHeader.setConsumerGroup(groupName); @@ -172,8 +172,8 @@ public class Converter { } public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); @@ -188,8 +188,8 @@ public class Converter { public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, DelayPolicy delayPolicy) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); @@ -206,8 +206,8 @@ public class Converter { public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader( ChangeInvisibleDurationRequest request) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); @@ -223,8 +223,8 @@ public class Converter { public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( ForwardMessageToDeadLetterQueueRequest request) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); @@ -240,8 +240,8 @@ public class Converter { public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( NackMessageRequest request) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); String receiptHandleStr = request.getReceiptHandle(); ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); @@ -256,7 +256,7 @@ public class Converter { } public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request) { - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String messageId = request.getMessageId(); String transactionId = request.getTransactionId(); TransactionId handle; @@ -268,7 +268,7 @@ public class Converter { long transactionStateTableOffset = handle.getTranStateTableOffset(); long commitLogOffset = handle.getCommitLogOffset(); boolean fromTransactionCheck = request.getSource() == EndTransactionRequest.Source.SERVER_CHECK; - int commitOrRollback = Converter.buildTransactionCommitOrRollback(request.getResolution()); + int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); endTransactionRequestHeader.setProducerGroup(groupName); @@ -284,13 +284,13 @@ public class Converter { public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { Partition partition = request.getPartition(); - String groupName = Converter.getResourceNameWithNamespace(request.getGroup()); - String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); int queueId = partition.getId(); int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); String expression = request.getFilterExpression().getExpression(); - String expressionType = Converter.buildExpressionType(request.getFilterExpression().getType()); + String expressionType = GrpcConverter.buildExpressionType(request.getFilterExpression().getType()); PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); requestHeader.setConsumerGroup(groupName); @@ -370,7 +370,7 @@ public class Converter { MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); // set producer group Resource producerGroup = message.getSystemAttribute().getProducerGroup(); - String producerGroupName = getResourceNameWithNamespace(producerGroup); + String producerGroupName = wrapResourceWithNamespace(producerGroup); MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroupName); // set message group String messageGroup = message.getSystemAttribute().getMessageGroup(); @@ -386,7 +386,7 @@ public class Converter { } public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage) { - String topic = getResourceNameWithNamespace(protoMessage.getTopic()); + String topic = wrapResourceWithNamespace(protoMessage.getTopic()); org.apache.rocketmq.common.message.Message message = new org.apache.rocketmq.common.message.Message(topic, protoMessage.getBody().toByteArray()); @@ -420,13 +420,13 @@ public class Converter { public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(ProducerData producerData) { org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); - buildProducerData.setGroupName(getResourceNameWithNamespace(producerData.getGroup())); + buildProducerData.setGroupName(wrapResourceWithNamespace(producerData.getGroup())); return buildProducerData; } public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(ConsumerData consumerData) { org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); - buildConsumerData.setGroupName(getResourceNameWithNamespace(consumerData.getGroup())); + buildConsumerData.setGroupName(wrapResourceWithNamespace(consumerData.getGroup())); buildConsumerData.setConsumeType(buildConsumeType(consumerData.getConsumeType())); buildConsumerData.setMessageModel(buildMessageModel(consumerData.getConsumeModel())); buildConsumerData.setConsumeFromWhere(buildConsumeFromWhere(consumerData.getConsumePolicy())); @@ -472,7 +472,7 @@ public class Converter { public static Set buildSubscriptionDataSet(List subscriptionEntryList) { Set subscriptionDataSet = new HashSet<>(); for (SubscriptionEntry sub : subscriptionEntryList) { - String topicName = Converter.getResourceNameWithNamespace(sub.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); FilterExpression filterExpression = sub.getExpression(); subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); } @@ -481,7 +481,7 @@ public class Converter { public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { String expression = filterExpression.getExpression(); - String expressionType = Converter.buildExpressionType(filterExpression.getType()); + String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); try { return FilterAPI.build(topicName, expression, expressionType); } catch (Exception e) { @@ -693,10 +693,10 @@ public class Converter { UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); header.setClientID(request.getClientId()); if (request.hasProducerGroup()) { - header.setProducerGroup(getResourceNameWithNamespace(request.getProducerGroup())); + header.setProducerGroup(wrapResourceWithNamespace(request.getProducerGroup())); } if (request.hasConsumerGroup()) { - header.setConsumerGroup(getResourceNameWithNamespace(request.getConsumerGroup())); + header.setConsumerGroup(wrapResourceWithNamespace(request.getConsumerGroup())); } return header; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java index 7561a21bc4..47641cf700 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ParameterConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java similarity index 84% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java index 122077b542..0bd79de2b6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseFuture.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java @@ -15,18 +15,18 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; -public class PollCommandResponseFuture { +public class PollResponseFuture { private final String commandId; private final Integer opaque; - public PollCommandResponseFuture(String commandId, int opaque) { + public PollResponseFuture(String commandId, int opaque) { this.commandId = commandId; this.opaque = opaque; } - public PollCommandResponseFuture(String commandId) { + public PollResponseFuture(String commandId) { this.commandId = commandId; this.opaque = null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java similarity index 77% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java index 0311788756..8379fdf4c8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/PollCommandResponseManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java @@ -15,23 +15,23 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; -public class PollCommandResponseManager { - private final ConcurrentMap futureTable = new ConcurrentHashMap<>(); +public class PollResponseManager { + private final ConcurrentMap futureTable = new ConcurrentHashMap<>(); private final AtomicLong commandIdGenerator = new AtomicLong(0); public String putResponse(int opaque) { String commandId = String.valueOf(commandIdGenerator.incrementAndGet()); - futureTable.put(commandId, new PollCommandResponseFuture(commandId, opaque)); + futureTable.put(commandId, new PollResponseFuture(commandId, opaque)); return commandId; } - public PollCommandResponseFuture getResponse(String commandId) { + public PollResponseFuture getResponse(String commandId) { return futureTable.get(commandId); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java index f476044383..da19dafc4e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; import com.google.rpc.Code; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java index 25ac8665f6..73856c64b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyMode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; public enum ProxyMode { LOCAL("LOCAL"), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java index 2134cb6eb3..0c1fa6ee00 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ProxyResponseCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; public enum ProxyResponseCode { SYS_ERR, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java index 7902014e02..d475d11fa1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.ResponseCommon; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java index 6af3052142..2a0a2bac08 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseHook.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; public interface ResponseHook { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java index 5d8fff2998..01965c8399 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/common/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.common; +package org.apache.rocketmq.proxy.grpc.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index 65bd2ad5eb..5e7f79f6a9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -30,8 +30,8 @@ import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { @@ -39,9 +39,9 @@ public class GrpcClientChannel extends SimpleChannel { private final String group; private final String clientId; - private final PollCommandResponseManager manager; + private final PollResponseManager manager; - private GrpcClientChannel(String group, String clientId, PollCommandResponseManager manager) { + private GrpcClientChannel(String group, String clientId, PollResponseManager manager) { super(ChannelManager.createSimpleChannelDirectly()); this.group = group; this.clientId = clientId; @@ -56,7 +56,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollCommandResponseManager manager + PollResponseManager manager ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), @@ -103,7 +103,7 @@ public class GrpcClientChannel extends SimpleChannel { future.complete(PollCommandResponse.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(requestHeader.getTransactionId()) - .setOrphanedTransactionalMessage(Converter.buildMessage(messageExt)) + .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) .build()) .build()); break; @@ -123,7 +123,7 @@ public class GrpcClientChannel extends SimpleChannel { break; } } - } catch (Exception e) { + } catch (Exception ignore) { } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java index ce85e2e4fe..7344d5f451 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java @@ -26,12 +26,13 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class PullMessageResponseHandler implements ResponseHandler { - @Override public void handle(RemotingCommand responseCommand, + @Override + public void handle(RemotingCommand responseCommand, InvocationContext context) { try { PullMessageResponseHeader responseHeader = (PullMessageResponseHeader) responseCommand.readCustomHeader(); @@ -40,7 +41,7 @@ public class PullMessageResponseHandler implements ResponseHandler msgFoundList = MessageDecoder.decodes(byteBuffer); for (MessageExt messageExt : msgFoundList) { - builder.addMessages(Converter.buildMessage(messageExt)); + builder.addMessages(GrpcConverter.buildMessage(messageExt)); } } PullMessageResponse response = builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java index f85cf4cc41..82b5127067 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java @@ -37,8 +37,8 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; import org.slf4j.Logger; @@ -122,7 +122,7 @@ public class ReceiveMessageResponseHandler implements ResponseHandler { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 63bee24262..d74f83220b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -64,10 +64,10 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.service.cluster.ClientService; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.service.cluster.ForwardClientService; import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; @@ -87,19 +87,19 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ProducerService producerService; private final ConsumerService receiveMessageService; private final RouteService routeService; - private final ClientService clientService; + private final ForwardClientService clientService; private final PullMessageService pullMessageService; private final TransactionService transactionService; - private final PollCommandResponseManager pollCommandResponseManager; + private final PollResponseManager pollCommandResponseManager; public ClusterGrpcService() { this.channelManager = new ChannelManager(); - this.pollCommandResponseManager = new PollCommandResponseManager(); + this.pollCommandResponseManager = new PollResponseManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.receiveMessageService = new ConsumerService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); - this.clientService = new ClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); + this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index d4c2cce67b..3565be03c8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -98,12 +98,12 @@ import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseFuture; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseFuture; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; import org.apache.rocketmq.remoting.RemotingServer; @@ -120,7 +120,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; - private final PollCommandResponseManager pollCommandResponseManager; + private final PollResponseManager pollCommandResponseManager; private final RouteService routeService; private final DelayPolicy delayPolicy; @@ -129,7 +129,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.channelManager = new ChannelManager(); // TransactionStateChecker is not used in Local mode. ConnectorManager connectorManager = new ConnectorManager(null); - this.pollCommandResponseManager = new PollCommandResponseManager(); + this.pollCommandResponseManager = new PollResponseManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.appendStartAndShutdown(connectorManager); @@ -146,17 +146,17 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo LanguageCode languageCode; String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); languageCode = LanguageCode.valueOf(language); - HeartbeatData heartbeatData = Converter.buildHeartbeatData(request); + HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(request); CompletableFuture future = new CompletableFuture<>(); String groupName; switch (request.getClientDataCase()) { case PRODUCER_DATA: { - groupName = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); + groupName = GrpcConverter.wrapResourceWithNamespace(request.getProducerData().getGroup()); break; } case CONSUMER_DATA: { - groupName = Converter.getResourceNameWithNamespace(request.getConsumerData().getGroup()); + groupName = GrpcConverter.wrapResourceWithNamespace(request.getConsumerData().getGroup()); break; } default: { @@ -191,7 +191,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - SendMessageRequestHeader requestHeader = Converter.buildSendMessageRequestHeader(request); + SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); Message message = request.getMessage(); command.setBody(message.getBody().toByteArray()); @@ -233,7 +233,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo if (pollTime <= 0) { pollTime = timeRemaining; } - PopMessageRequestHeader requestHeader = Converter.buildPopMessageRequestHeader(request, pollTime); + PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -262,7 +262,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - AckMessageRequestHeader requestHeader = Converter.buildAckMessageRequestHeader(request); + AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -289,7 +289,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -314,7 +314,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ConsumerSendMsgBackRequestHeader requestHeader = Converter.buildConsumerSendMsgBackRequestHeader(request); + ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); command.makeCustomHeaderToNet(); @@ -344,7 +344,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - EndTransactionRequestHeader requestHeader = Converter.buildEndTransactionRequestHeader(request); + EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); command.makeCustomHeaderToNet(); @@ -370,7 +370,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { Partition partition = request.getPartition(); - String topicName = Converter.getResourceNameWithNamespace(partition.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); int queueId = partition.getId(); long offset; @@ -399,7 +399,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo if (pollTime <= 0) { pollTime = timeRemaining; } - PullMessageRequestHeader requestHeader = Converter.buildPullMessageRequestHeader(request, pollTime); + PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -431,7 +431,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo switch (request.getGroupCase()) { case PRODUCER_GROUP: Resource producerGroup = request.getProducerGroup(); - String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); + String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); if (producerChannel == null) { future.complete(PollCommandResponse.newBuilder() @@ -443,7 +443,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo break; case CONSUMER_GROUP: Resource consumerGroup = request.getConsumerGroup(); - String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); + String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); if (consumerChannel == null) { future.complete(PollCommandResponse.newBuilder() @@ -464,7 +464,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ReportThreadStackTraceRequest request) { String commandId = request.getCommandId(); String threadStack = request.getThreadStackTrace(); - PollCommandResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); + PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); if (pollCommandResponseFuture != null) { RemotingServer remotingServer = this.brokerController.getRemotingServer(); if (remotingServer instanceof NettyRemotingAbstract) { @@ -487,14 +487,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ReportMessageConsumptionResultRequest request) { String commandId = request.getCommandId(); - PollCommandResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); + PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); if (pollCommandResponseFuture != null) { RemotingServer remotingServer = this.brokerController.getRemotingServer(); if (remotingServer instanceof NettyRemotingAbstract) { NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumeMessageDirectlyResult result = Converter.buildConsumeMessageDirectlyResult(request); + ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); remotingCommand.setBody(result.encode()); nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); } @@ -509,7 +509,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo NotifyClientTerminationRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - UnregisterClientRequestHeader header = Converter.buildUnregisterClientRequestHeader(request); + UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); remotingCommand.makeCustomHeaderToNet(); @@ -526,7 +526,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = Converter.buildChangeInvisibleTimeRequestHeader(request); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index fd2854da15..2c7bb94d3d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -21,7 +21,7 @@ import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; public class BaseService { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index d6975e6892..56c207a295 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -44,10 +44,10 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; import java.util.ArrayList; import java.util.List; @@ -115,7 +115,7 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader convertToPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { // check filterExpression is correct or not - Converter.buildSubscriptionData(Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + GrpcConverter.buildSubscriptionData(GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); long timeRemaining = ctx.getDeadline() .timeRemaining(TimeUnit.MILLISECONDS); @@ -124,12 +124,12 @@ public class ConsumerService extends BaseService { pollTime = timeRemaining; } - return Converter.buildPopMessageRequestHeader(request, pollTime); + return GrpcConverter.buildPopMessageRequestHeader(request, pollTime); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { - SubscriptionData subscriptionData = Converter.buildSubscriptionData( - Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( + GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); PopStatus status = result.getPopStatus(); switch (status) { case FOUND: @@ -152,7 +152,7 @@ public class ConsumerService extends BaseService { this.ackNoMatchedMessage(ctx, request, messageExt); continue; } - messages.add(Converter.buildMessage(messageExt)); + messages.add(GrpcConverter.buildMessage(messageExt)); } return ReceiveMessageResponse.newBuilder() @@ -170,7 +170,7 @@ public class ConsumerService extends BaseService { return; } String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); - ackMessageRequestHeader.setConsumerGroup(Converter.getResourceNameWithNamespace(request.getGroup())); + ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); ackMessageRequestHeader.setTopic(messageExt.getTopic()); ackMessageRequestHeader.setQueueId(handle.getQueueId()); ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); @@ -219,7 +219,7 @@ public class ConsumerService extends BaseService { } protected AckMessageRequestHeader convertToAckMessageRequestHeader(Context ctx, AckMessageRequest request) { - return Converter.buildAckMessageRequestHeader(request); + return GrpcConverter.buildAckMessageRequestHeader(request); } protected AckMessageResponse convertToAckMessageResponse(Context ctx, AckMessageRequest request, AckResult ackResult) { @@ -286,11 +286,11 @@ public class ConsumerService extends BaseService { } protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return Converter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); } protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request) { - return Converter.buildConsumerSendMsgBackToDLQRequestHeader(request); + return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java index 92ea26eb5a..d81f9c92b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java @@ -22,7 +22,7 @@ import java.util.List; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @@ -34,7 +34,7 @@ public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @Override public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { - String topicName = Converter.getResourceNameWithNamespace(request.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topicName); return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java similarity index 75% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index 69aa281186..6c2c66268e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -24,6 +24,7 @@ import apache.rocketmq.v1.PollCommandRequest; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.Resource; import io.grpc.Context; +import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -33,35 +34,40 @@ import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ClientService extends BaseService { - - private static final Logger log = LoggerFactory.getLogger(ClientService.class); +public class ForwardClientService extends BaseService { + private static final Logger LOGGER = LoggerFactory.getLogger(ForwardClientService.class); private final ChannelManager channelManager; - private final ConsumerManager consumerManager = new ConsumerManager((event, group, args) -> { - }); + private final ConsumerManager consumerManager; private final ProducerManager producerManager; - private final PollCommandResponseManager pollCommandResponseManager; + private final PollResponseManager pollCommandResponseManager; - public ClientService( + public ForwardClientService( ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager, - PollCommandResponseManager pollCommandResponseManager + PollResponseManager pollCommandResponseManager ) { super(connectorManager); - scheduledExecutorService.scheduleWithFixedDelay(this::scanNotActiveChannel, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); + scheduledExecutorService.scheduleWithFixedDelay( + this::scanNotActiveChannel, + Duration.ofSeconds(10).toMillis(), + Duration.ofSeconds(10).toMillis(), + TimeUnit.MILLISECONDS); this.channelManager = channelManager; this.pollCommandResponseManager = pollCommandResponseManager; + this.consumerManager = new ConsumerManager((event, group, args) -> { + // nothing to do in handler. + }); this.producerManager = new ProducerManager(); this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); } @@ -72,7 +78,7 @@ public class ClientService extends BaseService { String clientId = request.getClientId(); if (request.hasProducerData()) { - String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerData().getGroup()); + String producerGroup = GrpcConverter.wrapResourceWithNamespace(request.getProducerData().getGroup()); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); producerManager.registerProducer(producerGroup, clientChannelInfo); @@ -80,17 +86,17 @@ public class ClientService extends BaseService { if (request.hasConsumerData()) { ConsumerData consumerData = request.getConsumerData(); - String consumerGroup = Converter.getResourceNameWithNamespace(consumerData.getGroup()); + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(consumerData.getGroup()); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, consumerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); consumerManager.registerConsumer( consumerGroup, clientChannelInfo, - Converter.buildConsumeType(consumerData.getConsumeType()), - Converter.buildMessageModel(consumerData.getConsumeModel()), - Converter.buildConsumeFromWhere(consumerData.getConsumePolicy()), - Converter.buildSubscriptionDataSet(consumerData.getSubscriptionsList()), + GrpcConverter.buildConsumeType(consumerData.getConsumeType()), + GrpcConverter.buildMessageModel(consumerData.getConsumeModel()), + GrpcConverter.buildConsumeFromWhere(consumerData.getConsumePolicy()), + GrpcConverter.buildSubscriptionDataSet(consumerData.getSubscriptionsList()), false ); } @@ -100,7 +106,7 @@ public class ClientService extends BaseService { String clientId = request.getClientId(); if (request.hasProducerGroup()) { - String producerGroup = Converter.getResourceNameWithNamespace(request.getProducerGroup()); + String producerGroup = GrpcConverter.wrapResourceWithNamespace(request.getProducerGroup()); GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, producerGroup, clientId); if (channel != null) { producerManager.doChannelCloseEvent(producerGroup, channel); @@ -108,7 +114,7 @@ public class ClientService extends BaseService { } if (request.hasConsumerGroup()) { - String consumerGroup = Converter.getResourceNameWithNamespace(request.getConsumerGroup()); + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getConsumerGroup()); GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); if (channel != null) { consumerManager.doChannelCloseEvent(consumerGroup, channel); @@ -118,13 +124,15 @@ public class ClientService extends BaseService { public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { CompletableFuture future = new CompletableFuture<>(); - String clientId = request.getClientId(); - PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand(NoopCommand.newBuilder().build()).build(); + PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand( + NoopCommand.newBuilder().build() + ).build(); + String clientId = request.getClientId(); switch (request.getGroupCase()) { case PRODUCER_GROUP: Resource producerGroup = request.getProducerGroup(); - String producerGroupName = Converter.getResourceNameWithNamespace(producerGroup); + String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(this.channelManager, producerGroupName, clientId); if (producerChannel == null) { future.complete(noopCommandResponse); @@ -134,7 +142,7 @@ public class ClientService extends BaseService { break; case CONSUMER_GROUP: Resource consumerGroup = request.getConsumerGroup(); - String consumerGroupName = Converter.getResourceNameWithNamespace(consumerGroup); + String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(this.channelManager, consumerGroupName, clientId); if (consumerChannel == null) { future.complete(noopCommandResponse); @@ -153,7 +161,7 @@ public class ClientService extends BaseService { this.consumerManager.scanNotActiveChannel(); this.producerManager.scanNotActiveChannel(); } catch (Exception e) { - log.error("error occurred when scan not active client channels.", e); + LOGGER.error("error occurred when scan not active client channels.", e); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 0435c8f794..dfb8837799 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -34,10 +34,10 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ProxyException; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerService extends BaseService { @@ -110,7 +110,7 @@ public class ProducerService extends BaseService { protected Pair convertSendMessageRequest( Context ctx, SendMessageRequest request) { - return Pair.of(Converter.buildSendMessageRequestHeader(request), Converter.buildMessage(request.getMessage())); + return Pair.of(GrpcConverter.buildSendMessageRequestHeader(request), GrpcConverter.buildMessage(request.getMessage())); } protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, @@ -123,8 +123,8 @@ public class ProducerService extends BaseService { if (StringUtils.isNotBlank(sendResult.getTransactionId())) { Message message = request.getMessage(); - String group = Converter.getResourceNameWithNamespace(message.getSystemAttribute().getProducerGroup()); - String topic = Converter.getResourceNameWithNamespace(message.getTopic()); + String group = GrpcConverter.wrapResourceWithNamespace(message.getSystemAttribute().getProducerGroup()); + String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); this.connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(group, topic); } @@ -169,6 +169,6 @@ public class ProducerService extends BaseService { protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackRequestHeader(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return Converter.buildConsumerSendMsgBackRequestHeader(request); + return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 6d7adab3da..93b87b9ad2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -39,10 +39,10 @@ import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ProxyException; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class PullMessageService extends BaseService { @@ -66,7 +66,7 @@ public class PullMessageService extends BaseService { }); try { Partition partition = request.getPartition(); - String topic = Converter.getResourceNameWithNamespace(partition.getTopic()); + String topic = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); String brokerName = partition.getBroker().getName(); int queueId = partition.getId(); @@ -133,14 +133,14 @@ public class PullMessageService extends BaseService { protected PullMessageRequestHeader convertToPullMessageRequestHeader(Context ctx, PullMessageRequest request) { // check filterExpression is correct or not - Converter.buildSubscriptionData(Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + GrpcConverter.buildSubscriptionData(GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); long pollTime = ctx.getDeadline() .timeRemaining(TimeUnit.MILLISECONDS) - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); if (pollTime <= 0) { throw new ProxyException(Code.DEADLINE_EXCEEDED, "request has been canceled due to timeout"); } - return Converter.buildPullMessageRequestHeader(request, pollTime); + return GrpcConverter.buildPullMessageRequestHeader(request, pollTime); } protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { @@ -150,14 +150,14 @@ public class PullMessageService extends BaseService { .setMaxOffset(result.getMaxOffset()) .setNextOffset(result.getNextBeginOffset()); - SubscriptionData subscriptionData = Converter.buildSubscriptionData( - Converter.getResourceNameWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( + GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); PullStatus status = result.getPullStatus(); if (status.equals(PullStatus.FOUND)) { List messageList = result.getMsgFoundList().stream() .filter(msg -> FilterUtils.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. - .map(Converter::buildMessage) + .map(GrpcConverter::buildMessage) .collect(Collectors.toList()); return responseBuilder.addAllMessages(messageList).build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 37d4acb047..6513dc68b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -46,11 +46,11 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class RouteService extends BaseService { private final ProxyMode mode; @@ -103,7 +103,7 @@ public class RouteService extends BaseService { try { MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() - .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + .getMessageQueue(GrpcConverter.wrapResourceWithNamespace(request.getTopic())); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); List brokerDataList = topicRouteData.getBrokerDatas(); @@ -218,7 +218,7 @@ public class RouteService extends BaseService { List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); if (ProxyMode.isLocalMode(mode)) { MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() - .getMessageQueue(Converter.getResourceNameWithNamespace(request.getTopic())); + .getMessageQueue(GrpcConverter.wrapResourceWithNamespace(request.getTopic())); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); for (SelectableMessageQueue messageQueue : messageQueueList) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index 3484ddfa01..48ffd2e402 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -34,9 +34,9 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.common.Converter; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class TransactionService extends BaseService implements TransactionStateChecker { @@ -62,7 +62,7 @@ public class TransactionService extends BaseService implements TransactionStateC GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); String transactionId = checkData.getTransactionId().getProxyTransactionId(); - Message message = Converter.buildMessage(checkData.getMessageExt()); + Message message = GrpcConverter.buildMessage(checkData.getMessageExt()); PollCommandResponse response = PollCommandResponse.newBuilder() .setRecoverOrphanedTransactionCommand( RecoverOrphanedTransactionCommand.newBuilder() @@ -102,7 +102,7 @@ public class TransactionService extends BaseService implements TransactionStateC } protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { - return Converter.buildEndTransactionRequestHeader(request); + return GrpcConverter.buildEndTransactionRequestHeader(request); } public void setCheckTransactionStateHook( diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java index 92ad3a362a..0d36a23c73 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/common/utils/FilterUtilTest.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.common.utils; -import java.util.concurrent.ThreadLocalRandom; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.junit.Test; @@ -26,25 +25,25 @@ import static org.assertj.core.api.Assertions.assertThat; public class FilterUtilTest { @Test - public void testIsTagMatched() throws Exception { + public void testTagMatched() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); } @Test - public void testIsTagNotMatched() throws Exception { + public void testTagNotMatched() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagB")).isFalse(); } @Test - public void testIsTagMatchedStar() throws Exception { + public void testTagMatchedStar() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "*"); assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), "tagA")).isTrue(); } @Test - public void testIsTagNotMatchedNull() throws Exception { + public void testTagNotMatchedNull() throws Exception { SubscriptionData subscriptionData = FilterAPI.buildSubscriptionData("", "tagA"); assertThat(FilterUtils.isTagMatched(subscriptionData.getTagsSet(), null)).isFalse(); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java index 669efe8ca2..ea3943a838 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java index b2061744cb..01d89f4472 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java @@ -28,24 +28,26 @@ import static org.assertj.core.api.Assertions.assertThat; public class ForwardClientManagerTest extends InitConfigAndLoggerTest { @Test - public void testClientManager() throws Exception { + public void testConnectorManager() throws Exception { TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); - ConnectorManager clientManager = new ConnectorManager(mockedTransactionStateChecker); - clientManager.start(); + ConnectorManager connectorManager = new ConnectorManager(mockedTransactionStateChecker); + connectorManager.start(); - assertThat(clientManager.getDefaultForwardClient()).isNotNull(); - assertThat(clientManager.getDefaultForwardClient().getClientNum()) + assertThat(connectorManager.getDefaultForwardClient()).isNotNull(); + assertThat(connectorManager.getDefaultForwardClient().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultForwardClientNum()); - assertThat(clientManager.getForwardProducer()).isNotNull(); - assertThat(clientManager.getForwardProducer().getClientNum()) + assertThat(connectorManager.getForwardProducer()).isNotNull(); + assertThat(connectorManager.getForwardProducer().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getForwardProducerNum()); - assertThat(clientManager.getForwardReadConsumer()).isNotNull(); - assertThat(clientManager.getForwardReadConsumer().getClientNum()) + assertThat(connectorManager.getForwardReadConsumer()).isNotNull(); + assertThat(connectorManager.getForwardReadConsumer().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); - + assertThat(connectorManager.getForwardWriteConsumer()).isNotNull(); + assertThat(connectorManager.getForwardWriteConsumer().getClientNum()) + .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index e473b039c9..bbe999cecb 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -77,7 +77,7 @@ import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -263,7 +263,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); assertThat(r.getMessagesCount()).isEqualTo(1); assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); - assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); + assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); } @@ -563,7 +563,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { PullMessageResponse r = grpcFuture.get(); assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); assertThat(r.getMessagesCount()).isEqualTo(1); - assertThat(Converter.getResourceNameWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); + assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); assertThat(r.getMinOffset()).isEqualTo(minOffset); assertThat(r.getNextOffset()).isEqualTo(nextOffset); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java index 21accfcf1e..72324a7a2f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java @@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.common.Converter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -61,8 +61,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - Converter.buildSendMessageRequestHeader(request), - Converter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request), + GrpcConverter.buildMessage(request.getMessage())); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -85,8 +85,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - Converter.buildSendMessageRequestHeader(request), - Converter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request), + GrpcConverter.buildMessage(request.getMessage())); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -108,8 +108,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - Converter.buildSendMessageRequestHeader(request), - Converter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request), + GrpcConverter.buildMessage(request.getMessage())); assertEquals("selectNormalQueue", queue.getBrokerName()); assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); @@ -136,8 +136,8 @@ public class DefaultProducerQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - Converter.buildSendMessageRequestHeader(request), - Converter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request), + GrpcConverter.buildMessage(request.getMessage())); assertEquals("selectTargetQueue", queue.getBrokerName()); assertEquals("selectTargetQueueAddr", queue.getBrokerAddr()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 708d683d76..6a56bfd544 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -31,7 +31,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 73761cd9b3..4c8a3a4380 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -38,7 +38,7 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; From a613f6c4f379e832b7f593b6191e5775b8a2fed3 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 25 Mar 2022 16:45:54 +0800 Subject: [PATCH 069/338] [ISSUE #3949] add test cases --- .../apache/rocketmq/proxy/ProxyStartup.java | 1 + .../proxy/channel/ChannelManager.java | 8 +- .../proxy/connector/ForwardProducer.java | 14 +- .../proxy/grpc/GrpcMessagingProcessor.java | 96 ++++++++-- .../proxy/grpc/adapter/DelayPolicy.java | 5 +- .../proxy/grpc/adapter/GrpcConverter.java | 10 +- .../proxy/grpc/adapter/ResponseHook.java | 4 +- .../proxy/grpc/adapter/ResponseWriter.java | 13 +- .../adapter/channel/GrpcClientChannel.java | 27 ++- .../grpc/service/ClusterGrpcService.java | 6 +- .../grpc/service/cluster/ConsumerService.java | 13 +- .../service/cluster/ForwardClientService.java | 18 +- .../grpc/service/cluster/ProducerService.java | 4 +- .../service/cluster/PullMessageService.java | 11 +- .../grpc/service/cluster/RouteService.java | 4 +- .../service/cluster/TransactionService.java | 18 +- .../proxy/config/InitConfigAndLoggerTest.java | 2 +- .../grpc/service/LocalGrpcServiceTest.java | 2 +- .../grpc/service/cluster/BaseServiceTest.java | 61 +++++- .../service/cluster/ClientServiceTest.java | 138 ++++++++++++++ .../service/cluster/ConsumerServiceTest.java | 173 ++++++++++++++++++ .../cluster/DefaultReadQueueSelectorTest.java | 74 ++++++++ ...ava => DefaultWriteQueueSelectorTest.java} | 2 +- .../service/cluster/ProducerServiceTest.java | 13 +- .../cluster/PullMessageServiceTest.java | 134 ++++++++++++++ .../service/cluster/RouteServiceTest.java | 137 +++++++------- .../cluster/TransactionServiceTest.java | 94 ++++++++++ .../rocketmq/test/base/GrpcBaseTest.java | 20 ++ .../rocketmq/test/proxy/ClusterGrpcTest.java | 43 +++++ 29 files changed, 985 insertions(+), 160 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/{DefaultProducerQueueSelectorTest.java => DefaultWriteQueueSelectorTest.java} (98%) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java 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 27a21eb626..ccacf81d84 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -66,6 +66,7 @@ public class ProxyStartup { final HealthCheckServer healthCheckServer = new HealthCheckServer(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(healthCheckServer); + PROXY_START_AND_SHUTDOWN.start(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { LOGGER.info("try to shutdown server"); try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 9a25d1c45e..3719a487c0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -105,9 +105,13 @@ public class ChannelManager { } public static SimpleChannel createSimpleChannelDirectly() { - final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + return createSimpleChannelDirectly(Context.current()); + } + + public static SimpleChannel createSimpleChannelDirectly(Context ctx) { + final String clientHost = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + final String localAddress = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.LOCAL_ADDRESS); return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 835c8dbbd2..18b33d1799 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -58,19 +58,7 @@ public class ForwardProducer extends AbstractForwardClient { return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); } - public void endTransaction(EndTransactionRequestHeader request, long timeoutMillis) throws Exception { - TransactionId transactionId = TransactionId.decode(request.getTransactionId()); - - EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); - requestHeader.setProducerGroup(request.getProducerGroup()); - requestHeader.setTranStateTableOffset(transactionId.getTranStateTableOffset()); - requestHeader.setCommitLogOffset(transactionId.getCommitLogOffset()); - requestHeader.setFromTransactionCheck(request.getFromTransactionCheck()); - requestHeader.setMsgId(request.getMsgId()); - requestHeader.setTransactionId(transactionId.getBrokerTransactionId()); - requestHeader.setCommitOrRollback(request.getCommitOrRollback()); - - String brokerAddr = RemotingHelper.parseSocketAddressAddr(transactionId.getBrokerAddr()); + public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { this.getClient().endTransactionOneway( brokerAddr, requestHeader, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index fd2358e1fc..08414c5fbf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -50,13 +50,19 @@ import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; import apache.rocketmq.v1.ReportThreadStackTraceRequest; import apache.rocketmq.v1.ReportThreadStackTraceResponse; +import apache.rocketmq.v1.ResponseCommon; import apache.rocketmq.v1.SendMessageRequest; import apache.rocketmq.v1.SendMessageResponse; +import com.google.rpc.Code; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.grpc.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.common.ProxyException; +import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.common.ResponseWriter; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,12 +75,25 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic this.grpcForwardService = grpcForwardService; } + public ResponseCommon convertExceptionToResponseCommon(Throwable t) { + if (t instanceof CompletionException) { + if (t.getCause() instanceof ProxyException) { + ProxyException proxyException = (ProxyException) t.getCause(); + return ResponseBuilder.buildCommon(proxyException.getCode(), proxyException.getMessage()); + } + } + return ResponseBuilder.buildCommon(Code.INTERNAL, "internal error"); + } + @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.queryRoute(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + QueryRouteResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -84,7 +103,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.heartbeat(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + HeartbeatResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -94,7 +116,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.healthCheck(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + HealthCheckResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -104,7 +129,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + SendMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -114,7 +142,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.queryAssignment(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + QueryAssignmentResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -124,7 +155,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.receiveMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + ReceiveMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -134,7 +168,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + AckMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -144,7 +181,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.nackMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + NackMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -154,7 +194,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + ForwardMessageToDeadLetterQueueResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -164,7 +207,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.endTransaction(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + EndTransactionResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -174,7 +220,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.queryOffset(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + QueryOffsetResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -184,7 +233,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.pullMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + PullMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -204,7 +256,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.reportThreadStackTrace(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + ReportThreadStackTraceResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -214,7 +269,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.reportMessageConsumptionResult(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + ReportMessageConsumptionResultResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -224,7 +282,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + NotifyClientTerminationResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } @@ -234,7 +295,10 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); + ResponseWriter.write( + responseObserver, + ChangeInvisibleDurationResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() + ); return null; }); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java index 0f731a27dc..722910ae18 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java @@ -51,11 +51,12 @@ public class DelayPolicy { private static List buildList(String messageDelayLevel) { List delayLevelList = Lists.newArrayList(Splitter.on(" ").split(messageDelayLevel)); List delayIntervalList = new ArrayList<>(); + // the index of messageDelayLevel start from 1, so add a default value + delayIntervalList.add(0L); for (String delayLevel : delayLevelList) { final Pattern p = Pattern.compile("(\\d+)([smhd])"); final Matcher m = p.matcher(delayLevel); - while (m.find()) - { + while (m.find()) { final int duration = Integer.parseInt(m.group(1)); final String timeUnitString = m.group(2); final long interval = toInterval(duration, timeUnitString); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java index 2f067aee82..f53773da78 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java @@ -263,7 +263,7 @@ public class GrpcConverter { try { handle = TransactionId.decode(transactionId); } catch (UnknownHostException e) { - throw new IllegalArgumentException("Parse transaction id failed", e); + throw new ProxyException(Code.INVALID_ARGUMENT, "Parse transaction id failed", e); } long transactionStateTableOffset = handle.getTranStateTableOffset(); long commitLogOffset = handle.getCommitLogOffset(); @@ -273,7 +273,7 @@ public class GrpcConverter { EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); endTransactionRequestHeader.setProducerGroup(groupName); endTransactionRequestHeader.setMsgId(messageId); - endTransactionRequestHeader.setTransactionId(transactionId); + endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); @@ -313,7 +313,7 @@ public class GrpcConverter { Map userProperties = message.getUserAttributeMap(); for (String key : userProperties.keySet()) { if (MessageConst.STRING_HASH_SET.contains(key)) { - throw new IllegalArgumentException("Property is used by system: " + key); + throw new ProxyException(Code.INVALID_ARGUMENT, "property is used by system: " + key); } } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); @@ -333,7 +333,7 @@ public class GrpcConverter { // set message id String messageId = message.getSystemAttribute().getMessageId(); if ("".equals(messageId)) { - throw new IllegalArgumentException("message id is empty"); + throw new ProxyException(Code.INVALID_ARGUMENT, "message id is empty"); } MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); @@ -363,7 +363,7 @@ public class GrpcConverter { case TIMEDDELIVERY_NOT_SET: break; default: - throw new IllegalStateException("Unexpected value: " + message.getSystemAttribute().getTimedDeliveryCase()); + throw new ProxyException(Code.INVALID_ARGUMENT, "unexpected value: " + message.getSystemAttribute().getTimedDeliveryCase()); } // set reconsume times int reconsumeTimes = message.getSystemAttribute().getDeliveryAttempt(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java index 2a0a2bac08..f18f6dc19d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java @@ -16,7 +16,9 @@ */ package org.apache.rocketmq.proxy.grpc.adapter; +import io.grpc.Context; + public interface ResponseHook { - void beforeResponse(T request, R response, Throwable t); + void beforeResponse(Context ctx, T request, R response, Throwable t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java index 01965c8399..601e509de2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java @@ -44,9 +44,9 @@ public class ResponseWriter { } } - public static void writeException(StreamObserver observer, final Throwable e) { + public static void writeException(StreamObserver observer, final Throwable e) { if (observer instanceof ServerCallStreamObserver) { - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (null == e) { return; } @@ -56,6 +56,15 @@ public class ResponseWriter { return; } +// if (e instanceof CompletionException) { +// if (e.getCause() instanceof ProxyException) { +// ProxyException proxyException = (ProxyException) e.getCause(); +// serverCallStreamObserver.onNext(ResponseBuilder.buildCommon(proxyException.getCode(), proxyException.getMessage())); +// serverCallStreamObserver.onCompleted(); +// return; +// } +// } + LOGGER.debug("Start to write error response", e); serverCallStreamObserver.onError(e); serverCallStreamObserver.onCompleted(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index 5e7f79f6a9..b42d10728a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.PrintThreadStackTraceCommand; import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; +import io.grpc.Context; import io.netty.channel.ChannelFuture; import java.nio.ByteBuffer; import java.util.concurrent.CompletableFuture; @@ -42,7 +43,11 @@ public class GrpcClientChannel extends SimpleChannel { private final PollResponseManager manager; private GrpcClientChannel(String group, String clientId, PollResponseManager manager) { - super(ChannelManager.createSimpleChannelDirectly()); + this(Context.current(), group, clientId, manager); + } + + private GrpcClientChannel(Context ctx, String group, String clientId, PollResponseManager manager) { + super(ChannelManager.createSimpleChannelDirectly(ctx)); this.group = group; this.clientId = clientId; this.manager = manager; @@ -57,10 +62,20 @@ public class GrpcClientChannel extends SimpleChannel { String group, String clientId, PollResponseManager manager + ) { + return create(Context.current(), channelManager, group, clientId, manager); + } + + public static GrpcClientChannel create( + Context ctx, + ChannelManager channelManager, + String group, + String clientId, + PollCommandResponseManager manager ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), - () -> new GrpcClientChannel(group, clientId, manager), + () -> new GrpcClientChannel(ctx, group, clientId, manager), GrpcClientChannel.class ); @@ -80,6 +95,14 @@ public class GrpcClientChannel extends SimpleChannel { return group + "@" + clientId; } + @Override + public boolean isWritable() { + if (this.pollCommandResponseFutureRef.get() == null) { + return false; + } + return !this.pollCommandResponseFutureRef.get().isDone(); + } + /** * Write response to corresponding remote client * diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index d74f83220b..7268c107c5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -114,7 +114,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - this.clientService.heartbeat(ctx, request, channelManager); + this.clientService.heartbeat(ctx, request); return CompletableFuture.completedFuture( HeartbeatResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) @@ -196,8 +196,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request) { - this.clientService.unregister(ctx, request, channelManager); + NotifyClientTerminationRequest request) { + this.clientService.unregister(ctx, request); return CompletableFuture.completedFuture( NotifyClientTerminationResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 56c207a295..7d8c58d7ad 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -83,13 +83,17 @@ public class ConsumerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(request, response, throwable); + receiveMessageHook.beforeResponse(ctx, request, response, throwable); } }); try { PopMessageRequestHeader requestHeader = this.convertToPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); + if (messageQueue == null) { + throw new ProxyException(Code.NOT_FOUND, "no readable topic route for topic " + requestHeader.getTopic()); + } + CompletableFuture popResultFuture = this.readConsumer.popMessage( messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), @@ -182,7 +186,7 @@ public class ConsumerService extends BaseService { } future.whenComplete((ackResult, throwable) -> { if (ackNoMatchedMessageHook != null) { - ackNoMatchedMessageHook.beforeResponse(ackMessageRequestHeader, ackResult, throwable); + ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); } }); } @@ -191,7 +195,7 @@ public class ConsumerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (ackMessageHook != null) { - ackMessageHook.beforeResponse(request, response, throwable); + ackMessageHook.beforeResponse(ctx, request, response, throwable); } }); try { @@ -237,7 +241,7 @@ public class ConsumerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (nackMessageHook != null) { - nackMessageHook.beforeResponse(request, response, throwable); + nackMessageHook.beforeResponse(ctx, request, response, throwable); } }); try { @@ -258,7 +262,6 @@ public class ConsumerService extends BaseService { } }) .exceptionally(throwable -> { - throwable.printStackTrace(); future.completeExceptionally(throwable); return null; }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index 6c2c66268e..eb8144e34f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -72,14 +72,14 @@ public class ForwardClientService extends BaseService { this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); } - public void heartbeat(Context ctx, HeartbeatRequest request, ChannelManager channelManager) { - String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); + public void heartbeat(Context ctx, HeartbeatRequest request) { + String language = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE); LanguageCode languageCode = LanguageCode.valueOf(language); String clientId = request.getClientId(); if (request.hasProducerData()) { String producerGroup = GrpcConverter.wrapResourceWithNamespace(request.getProducerData().getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, producerGroup, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, producerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); producerManager.registerProducer(producerGroup, clientChannelInfo); } @@ -87,7 +87,7 @@ public class ForwardClientService extends BaseService { if (request.hasConsumerData()) { ConsumerData consumerData = request.getConsumerData(); String consumerGroup = GrpcConverter.wrapResourceWithNamespace(consumerData.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, consumerGroup, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, pollCommandResponseManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); consumerManager.registerConsumer( @@ -102,7 +102,7 @@ public class ForwardClientService extends BaseService { } } - public void unregister(Context ctx, NotifyClientTerminationRequest request, ChannelManager channelManager) { + public void unregister(Context ctx, NotifyClientTerminationRequest request) { String clientId = request.getClientId(); if (request.hasProducerGroup()) { @@ -164,4 +164,12 @@ public class ForwardClientService extends BaseService { LOGGER.error("error occurred when scan not active client channels.", e); } } + + public ConsumerManager getConsumerManager() { + return consumerManager; + } + + public ProducerManager getProducerManager() { + return producerManager; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index dfb8837799..e924e28855 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -68,7 +68,7 @@ public class ProducerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (sendMessageHook != null) { - sendMessageHook.beforeResponse(request, response, throwable); + sendMessageHook.beforeResponse(ctx, request, response, throwable); } }); @@ -140,7 +140,7 @@ public class ProducerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (forwardMessageToDLQHook != null) { - forwardMessageToDLQHook.beforeResponse(request, response, throwable); + forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); } }); try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 93b87b9ad2..caa870efd6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -61,7 +61,7 @@ public class PullMessageService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (queryOffsetHook != null) { - queryOffsetHook.beforeResponse(request, response, throwable); + queryOffsetHook.beforeResponse(ctx, request, response, throwable); } }); try { @@ -100,7 +100,7 @@ public class PullMessageService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (pullMessageHook != null) { - pullMessageHook.beforeResponse(request, response, throwable); + pullMessageHook.beforeResponse(ctx, request, response, throwable); } }); @@ -135,10 +135,11 @@ public class PullMessageService extends BaseService { // check filterExpression is correct or not GrpcConverter.buildSubscriptionData(GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); - long pollTime = ctx.getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS) - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + long timeRemaining = ctx.getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); if (pollTime <= 0) { - throw new ProxyException(Code.DEADLINE_EXCEEDED, "request has been canceled due to timeout"); + pollTime = timeRemaining; } return GrpcConverter.buildPullMessageRequestHeader(request, pollTime); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 6513dc68b4..7ec10d6b5a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -97,7 +97,7 @@ public class RouteService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (queryRouteHook != null) { - queryRouteHook.beforeResponse(request, response, throwable); + queryRouteHook.beforeResponse(ctx, request, response, throwable); } }); @@ -209,7 +209,7 @@ public class RouteService extends BaseService { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (queryAssignmentHook != null) { - queryAssignmentHook.beforeResponse(request, response, throwable); + queryAssignmentHook.beforeResponse(ctx, request, response, throwable); } }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index 48ffd2e402..1317490bc3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -26,11 +26,13 @@ import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; +import org.apache.commons.collections.CollectionUtils; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; @@ -54,9 +56,12 @@ public class TransactionService extends BaseService implements TransactionStateC @Override public void checkTransactionState(TransactionStateCheckRequest checkData) { + Context ctx = Context.current(); try { List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); - // if clientIdList's size is 0, here will throw: java.lang.IllegalArgumentException: bound must be positive + if (CollectionUtils.isEmpty(clientIdList)) { + return; + } String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); @@ -72,11 +77,11 @@ public class TransactionService extends BaseService implements TransactionStateC ).build(); channel.writeAndFlush(response); if (this.checkTransactionStateHook != null) { - this.checkTransactionStateHook.beforeResponse(checkData, response, null); + this.checkTransactionStateHook.beforeResponse(ctx, checkData, response, null); } } catch (Throwable t) { if (this.checkTransactionStateHook != null) { - this.checkTransactionStateHook.beforeResponse(checkData, null, t); + this.checkTransactionStateHook.beforeResponse(ctx, checkData, null, t); } } } @@ -85,13 +90,16 @@ public class TransactionService extends BaseService implements TransactionStateC CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { if (endTransactionHook != null) { - endTransactionHook.beforeResponse(request, response, throwable); + endTransactionHook.beforeResponse(ctx, request, response, throwable); } }); try { + TransactionId handle = TransactionId.decode(request.getTransactionId()); EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); - this.forwardProducer.endTransaction(requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + this.forwardProducer.endTransaction( + RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()), + requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); future.complete(EndTransactionResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .build()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java index 5b2fea4e38..12e8dd74f6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/InitConfigAndLoggerTest.java @@ -32,7 +32,7 @@ public class InitConfigAndLoggerTest { public static String mockProxyHome = "/mock/rmq/proxy/home"; @Before - public void before() throws Exception { + public void before() throws Throwable { URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); if (mockProxyHomeURL != null) { mockProxyHome = mockProxyHomeURL.toURI().getPath(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index bbe999cecb..899cc3cebc 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -107,7 +107,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { private Metadata metadata; @Before - public void setUp() throws Exception { + public void setUp() throws Throwable { super.before(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java index b29a248cb8..adae5ded25 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java @@ -16,12 +16,23 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.junit.Before; import org.junit.Ignore; import org.junit.runner.RunWith; @@ -32,10 +43,10 @@ import static org.mockito.Mockito.when; @Ignore @RunWith(MockitoJUnitRunner.Silent.class) -public abstract class BaseServiceTest { +public abstract class BaseServiceTest extends InitConfigAndLoggerTest { @Mock - protected ConnectorManager clientManager; + protected ConnectorManager connectorManager; @Mock protected DefaultForwardClient defaultClient; @Mock @@ -46,17 +57,53 @@ public abstract class BaseServiceTest { protected ForwardWriteConsumer writeConsumerClient; @Mock protected TopicRouteCache topicRouteCache; + @Mock + protected TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; @Before public void before() throws Throwable { - when(clientManager.getDefaultForwardClient()).thenReturn(defaultClient); - when(clientManager.getForwardProducer()).thenReturn(producerClient); - when(clientManager.getForwardReadConsumer()).thenReturn(readConsumerClient); - when(clientManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); - when(clientManager.getTopicRouteCache()).thenReturn(topicRouteCache); + super.before(); + when(connectorManager.getDefaultForwardClient()).thenReturn(defaultClient); + when(connectorManager.getForwardProducer()).thenReturn(producerClient); + when(connectorManager.getForwardReadConsumer()).thenReturn(readConsumerClient); + when(connectorManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); + when(connectorManager.getTopicRouteCache()).thenReturn(topicRouteCache); + when(connectorManager.getTransactionHeartbeatRegisterService()).thenReturn(transactionHeartbeatRegisterService); beforeEach(); } public abstract void beforeEach() throws Throwable; + + protected static ReceiptHandle createReceiptHandle() { + return ReceiptHandle.builder() + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName("brokerName") + .retrieveTime(System.currentTimeMillis()) + .invisibleTime(TimeUnit.SECONDS.toMillis(3)) + .queueId(ThreadLocalRandom.current().nextInt(8)) + .offset(ThreadLocalRandom.current().nextInt(1000)) + .commitLogOffset(ThreadLocalRandom.current().nextInt(1000)) + .build(); + } + + protected static MessageExt createMessageExt(String msgId, String tag) { + return createMessageExt(msgId, tag, createReceiptHandle().encode()); + } + + protected static MessageExt createMessageExt(String msgId, String tag, String handler) { + SocketAddress addr = RemotingUtil.string2SocketAddress("127.0.0.1:8080"); + MessageExt msg = new MessageExt(0, + System.currentTimeMillis(), + addr, + System.currentTimeMillis(), + addr, + msgId); + msg.setTopic("topic"); + msg.setBody("hello".getBytes(StandardCharsets.UTF_8)); + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TAGS, tag); + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, msgId); + MessageAccessor.putProperty(msg, MessageConst.PROPERTY_POP_CK, handler); + return msg; + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java new file mode 100644 index 0000000000..a099e25923 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java @@ -0,0 +1,138 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.ConsumeMessageType; +import apache.rocketmq.v1.ConsumeModel; +import apache.rocketmq.v1.ConsumePolicy; +import apache.rocketmq.v1.ConsumerData; +import apache.rocketmq.v1.FilterExpression; +import apache.rocketmq.v1.FilterType; +import apache.rocketmq.v1.HeartbeatRequest; +import apache.rocketmq.v1.NotifyClientTerminationRequest; +import apache.rocketmq.v1.ProducerData; +import apache.rocketmq.v1.Resource; +import apache.rocketmq.v1.SubscriptionEntry; +import io.grpc.Context; +import io.grpc.Metadata; +import io.netty.channel.Channel; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupInfo; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ClientServiceTest extends BaseServiceTest { + + private ChannelManager channelManager = new ChannelManager(); + private PollCommandResponseManager pollCommandResponseManager = new PollCommandResponseManager(); + + @Override + public void beforeEach() throws Throwable { + + } + + @Test + public void testProducerHeartbeat() { + ClientService clientService = new ClientService( + this.connectorManager, + Executors.newSingleThreadScheduledExecutor(), + this.channelManager, + this.pollCommandResponseManager); + + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "127.0.0.1:8080"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "127.0.0.1:8081"); + Context ctx = Context.current().withValue(InterceptorConstants.METADATA, metadata); + clientService.heartbeat(ctx, HeartbeatRequest.newBuilder() + .setClientId("clientId") + .setProducerData(ProducerData.newBuilder() + .setGroup(Resource.newBuilder() + .setName("producerGroup") + .build()) + .build()) + .build()); + + assertEquals(1, clientService.getProducerManager().getGroupChannelTable().size()); + Channel channel = clientService.getProducerManager().findChannel("clientId"); + assertNotNull(channel); + assertTrue(channel instanceof GrpcClientChannel); + + clientService.unregister(ctx, NotifyClientTerminationRequest.newBuilder() + .setClientId("clientId") + .setProducerGroup(Resource.newBuilder() + .setName("producerGroup") + .build()) + .build()); + assertTrue(clientService.getProducerManager().getGroupChannelTable().isEmpty()); + } + + @Test + public void testConsumerHeartbeat() { + ClientService clientService = new ClientService( + this.connectorManager, + Executors.newSingleThreadScheduledExecutor(), + this.channelManager, + this.pollCommandResponseManager); + + List subscriptionEntryList = new ArrayList<>(); + subscriptionEntryList.add(SubscriptionEntry.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setExpression(FilterExpression.newBuilder() + .setExpression("*") + .setType(FilterType.TAG) + .build()) + .build()); + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, "127.0.0.1:8080"); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, "127.0.0.1:8081"); + Context ctx = Context.current().withValue(InterceptorConstants.METADATA, metadata); + + clientService.heartbeat(ctx, HeartbeatRequest.newBuilder() + .setClientId("clientId") + .setConsumerData(ConsumerData.newBuilder() + .setGroup(Resource.newBuilder() + .setName("consumerGroup") + .build()) + .setConsumeType(ConsumeMessageType.PASSIVE) + .setConsumeModel(ConsumeModel.CLUSTERING) + .setConsumePolicy(ConsumePolicy.RESUME) + .addAllSubscriptions(subscriptionEntryList) + .build()) + .build()); + + ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", "clientId"); + assertNotNull(clientChannelInfo); + assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); + assertEquals("clientId", clientChannelInfo.getClientId()); + assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); + ConsumerGroupInfo consumerGroupInfo = clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup"); + assertEquals(MessageModel.CLUSTERING, consumerGroupInfo.getMessageModel()); + assertEquals(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, consumerGroupInfo.getConsumeFromWhere()); + assertEquals(ConsumeType.CONSUME_PASSIVELY, consumerGroupInfo.getConsumeType()); + assertEquals("TAG", consumerGroupInfo.getSubscriptionTable().get("topic").getExpressionType()); + assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); + + + clientService.unregister(ctx, NotifyClientTerminationRequest.newBuilder() + .setClientId("clientId") + .setConsumerGroup(Resource.newBuilder() + .setName("consumerGroup") + .build()) + .build()); + assertNull(clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup")); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java new file mode 100644 index 0000000000..554314af56 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java @@ -0,0 +1,173 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.AckMessageRequest; +import apache.rocketmq.v1.AckMessageResponse; +import apache.rocketmq.v1.FilterExpression; +import apache.rocketmq.v1.FilterType; +import apache.rocketmq.v1.NackMessageRequest; +import apache.rocketmq.v1.NackMessageResponse; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.Resource; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.assertj.core.util.Lists; +import org.junit.Test; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class ConsumerServiceTest extends BaseServiceTest { + + @Mock + private ReadQueueSelector readQueueSelector; + + private ConsumerService consumerService; + + @Override + public void beforeEach() throws Throwable { + consumerService = new ConsumerService(this.connectorManager); + consumerService.setReadQueueSelector(readQueueSelector); + } + + @Test + public void testReceiveMessage() throws Exception { + SelectableMessageQueue selectableMessageQueue = new SelectableMessageQueue( + new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); + when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); + + List messageExtList = Lists.newArrayList( + createMessageExt("msg1", "msg1"), + createMessageExt("msg2", "msg2")); + PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); + when(readConsumerClient.popMessage(anyString(), anyString(), any(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(popResult)); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + when(writeConsumerClient.ackMessage(anyString(), any(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(new AckResult())); + + Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); + AtomicReference ackHandler = new AtomicReference<>(); + consumerService.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); + ReceiveMessageResponse response = consumerService.receiveMessage(ctx, + ReceiveMessageRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.TAG) + .setExpression("msg1") + .build()) + .build() + ).get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getMessagesCount()); + assertEquals("msg1", response.getMessages(0).getSystemAttribute().getMessageId()); + assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); + } + + @Test + public void testAckMessage() throws Exception { + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.OK); + when(writeConsumerClient.ackMessage(anyString(), any(), anyLong())).thenReturn(CompletableFuture.completedFuture(ackResult)); + + AckMessageResponse response = consumerService.ackMessage(Context.current(), AckMessageRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setReceiptHandle(createReceiptHandle().encode()) + .build()) + .get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + } + + @Test + public void testNackMessageToDLQ() throws Exception { + ReceiptHandle receiptHandle = createReceiptHandle(); + AtomicReference headerRef = new AtomicReference<>(); + doAnswer(mock -> { + headerRef.set(mock.getArgument(1)); + return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); + }).when(producerClient).sendMessageBack(anyString(), any(), anyLong()); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + + NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setReceiptHandle(receiptHandle.encode()) + .setDeliveryAttempt(3) + .setMaxDeliveryAttempts(3) + .build()) + .get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(receiptHandle.getCommitLogOffset(), headerRef.get().getOffset().longValue()); + } + + @Test + public void testNackMessage() throws Exception { + ReceiptHandle receiptHandle = createReceiptHandle(); + AtomicReference headerRef = new AtomicReference<>(); + doAnswer(mock -> { + headerRef.set(mock.getArgument(2)); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.OK); + return CompletableFuture.completedFuture(ackResult); + }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any(), anyLong()); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + + NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setReceiptHandle(receiptHandle.encode()) + .setDeliveryAttempt(1) + .setMaxDeliveryAttempts(3) + .build()) + .get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(receiptHandle.getOffset(), headerRef.get().getOffset().longValue()); + assertEquals(receiptHandle.encode(), headerRef.get().getExtraInfo()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java new file mode 100644 index 0000000000..e44bfa595d --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java @@ -0,0 +1,74 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.ReceiveMessageRequest; +import io.grpc.Context; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.junit.Test; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.when; + +public class DefaultReadQueueSelectorTest extends BaseServiceTest { + + private final String brokerAddress = "127.0.0.1:10911"; + + @Override + public void beforeEach() throws Throwable { + } + + @Test + public void test() throws Exception { + SelectableMessageQueue messageQueue1 = new SelectableMessageQueue( + new MessageQueue("readBrokerTopicByName", "brokerName", 0), "brokerAddr1"); + SelectableMessageQueue messageQueue2 = new SelectableMessageQueue( + new MessageQueue("oneReadBroker", "brokerName", 0), "brokerAddr1"); + + when(topicRouteCache.selectReadBrokerByName(eq("readBrokerTopicByName"), anyString())).thenReturn(messageQueue1); + when(topicRouteCache.selectOneReadBroker(eq("oneReadBroker"), isNull())).thenReturn(messageQueue2); + + ReadQueueSelector readQueueSelector = new DefaultReadQueueSelector(topicRouteCache); + + { + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setTopic("readBrokerTopicByName"); + SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), + ReceiveMessageRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setBroker(Broker.newBuilder() + .setName("brokerName") + .build()) + .build()) + .build(), + requestHeader); + assertSame(messageQueue1, messageQueue); + } + + { + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setTopic("oneReadBroker"); + SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), + ReceiveMessageRequest.newBuilder() + .build(), + requestHeader); + assertSame(messageQueue2, messageQueue); + } + + { + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setTopic("topic"); + SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), + ReceiveMessageRequest.newBuilder() + .build(), + requestHeader); + assertNull(messageQueue); + } + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java index 72324a7a2f..222c64477b 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultProducerQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java @@ -21,7 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; -public class DefaultProducerQueueSelectorTest extends BaseServiceTest { +public class DefaultWriteQueueSelectorTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 6a56bfd544..871e91ac9e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -33,6 +33,8 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -42,6 +44,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; public class ProducerServiceTest extends BaseServiceTest { @@ -71,7 +74,7 @@ public class ProducerServiceTest extends BaseServiceTest { sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), 1L, "txId", "offsetMsgId", "regionId")); - ProducerService producerService = new ProducerService(this.clientManager); + ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); @@ -88,7 +91,7 @@ public class ProducerServiceTest extends BaseServiceTest { @Test public void testSendMessageNoQueueSelect() { - ProducerService producerService = new ProducerService(this.clientManager); + ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> null); @@ -125,7 +128,7 @@ public class ProducerServiceTest extends BaseServiceTest { .thenReturn(sendResultFuture); sendResultFuture.completeExceptionally(ex); - ProducerService producerService = new ProducerService(this.clientManager); + ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); @@ -145,11 +148,11 @@ public class ProducerServiceTest extends BaseServiceTest { public void testSendMessageWithErrorThrow() { RuntimeException ex = new RuntimeException(); - ProducerService producerService = new ProducerService(this.clientManager); + ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> { throw ex; }); - producerService.setSendMessageHook((request, response, t) -> { + producerService.setSendMessageHook((ctx, request, response, t) -> { assertSame(ex, t); }); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java new file mode 100644 index 0000000000..45277bf707 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java @@ -0,0 +1,134 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.Broker; +import apache.rocketmq.v1.FilterExpression; +import apache.rocketmq.v1.FilterType; +import apache.rocketmq.v1.Partition; +import apache.rocketmq.v1.PullMessageRequest; +import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v1.QueryOffsetPolicy; +import apache.rocketmq.v1.QueryOffsetRequest; +import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v1.Resource; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Timestamps; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.consumer.PullStatus; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.assertj.core.util.Lists; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class PullMessageServiceTest extends BaseServiceTest { + + private PullMessageService pullMessageService; + + @Override + public void beforeEach() throws Throwable { + pullMessageService = new PullMessageService(this.connectorManager); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + } + + @Test + public void testQueryOffset() throws Exception { + Context ctx = Context.current(); + + when(defaultClient.getMaxOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(CompletableFuture.completedFuture(100L)); + when(defaultClient.searchOffset(anyString(), anyString(), anyInt(), anyLong(), anyLong())).thenReturn(CompletableFuture.completedFuture(50L)); + + QueryOffsetResponse response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setBroker(Broker.newBuilder().setName("brokerName").build()) + .build()) + .setPolicy(QueryOffsetPolicy.BEGINNING) + .build() + ).get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(0, response.getOffset()); + + response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setBroker(Broker.newBuilder().setName("brokerName").build()) + .build()) + .setPolicy(QueryOffsetPolicy.END) + .build() + ).get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(100, response.getOffset()); + + response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setBroker(Broker.newBuilder().setName("brokerName").build()) + .build()) + .setTimePoint(Timestamps.fromMillis(System.currentTimeMillis())) + .setPolicy(QueryOffsetPolicy.TIME_POINT) + .build() + ).get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(50, response.getOffset()); + } + + @Test + public void testPullMessage() throws Exception { + AtomicReference headerRef = new AtomicReference<>(); + PullResult pullResult = new PullResult( + PullStatus.FOUND, + 3, + 0, + 10, + Lists.newArrayList( + createMessageExt("msg1", "msg1"), + createMessageExt("msg2", "msg2") + ) + ); + doAnswer(mock -> { + headerRef.set(mock.getArgument(1)); + return CompletableFuture.completedFuture(pullResult); + }).when(readConsumerClient).pullMessage(anyString(), any(), anyLong()); + + Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); + PullMessageResponse response = pullMessageService.pullMessage(ctx, PullMessageRequest.newBuilder() + .setPartition(Partition.newBuilder() + .setBroker(Broker.newBuilder() + .setName("brokerName") + .build()) + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()) + .setFilterExpression(FilterExpression.newBuilder() + .setExpression("msg1") + .setType(FilterType.TAG) + .build()) + .build()) + .get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getMessagesCount()); + assertEquals("msg1", response.getMessages(0).getSystemAttribute().getMessageId()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 4c8a3a4380..65a89b6888 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -35,15 +35,20 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.when; public class RouteServiceTest extends BaseServiceTest { private String brokerAddress = "127.0.0.1:10911"; @@ -57,7 +62,9 @@ public class RouteServiceTest extends BaseServiceTest { .build(); @Override - public void beforeEach() { + public void beforeEach() throws Exception { + TopicRouteData routeData = new TopicRouteData(); + List brokerDataList = new ArrayList<>(); BrokerData brokerData = new BrokerData(); brokerData.setCluster("cluster"); @@ -75,13 +82,21 @@ public class RouteServiceTest extends BaseServiceTest { queueData.setReadQueueNums(8); queueData.setBrokerName("brokerName"); queueDataList.add(queueData); + + routeData.setBrokerDatas(brokerDataList); + routeData.setQueueDatas(queueDataList); + + MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); + when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); + + when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); } @Test public void testGenPartitionFromQueueData() throws Exception { // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. QueueData queueDataWith8R8WPermRW = mockQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); @@ -89,7 +104,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. QueueData queueDataWith8R8WPermR = mockQueueData(8, 8, PermName.PERM_READ); - List partitionWith8R8WPermR = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermR = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermR.size()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -97,7 +112,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. QueueData queueDataWith8R8WPermW = mockQueueData(8, 8, PermName.PERM_WRITE); - List partitionWith8R8WPermW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -105,7 +120,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. QueueData queueDataWith8R0WPermRW = mockQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R0WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R0WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R0WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -113,7 +128,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. QueueData queueDataWith4R8WPermRW = mockQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith4R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith4R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith4R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(4); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(4); @@ -131,8 +146,8 @@ public class RouteServiceTest extends BaseServiceTest { } @Test - public void testLocalModeQueryRoute() { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.clientManager); + public void testLocalModeQueryRoute() throws Exception { + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setEndpoints(Endpoints.newBuilder() .addAddresses(Address.newBuilder() @@ -145,20 +160,16 @@ public class RouteServiceTest extends BaseServiceTest { .setName("topic") .build()) .build()); - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(8, response.getPartitionsCount()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getPartitions(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(8, response.getPartitionsCount()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getPartitions(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); } @Test - public void testQueryRouteWithInvalidEndpoints() { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + public void testQueryRouteWithInvalidEndpoints() throws Exception { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -166,17 +177,13 @@ public class RouteServiceTest extends BaseServiceTest { .build()) .build()); - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } + QueryRouteResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); } @Test - public void testQueryRoute() { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + public void testQueryRoute() throws Exception { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setEndpoints(Endpoints.newBuilder() @@ -191,20 +198,16 @@ public class RouteServiceTest extends BaseServiceTest { .build()) .build()); - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(8, response.getPartitionsCount()); - assertEquals("host", response.getPartitions(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(8, response.getPartitionsCount()); + assertEquals("host", response.getPartitions(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); } @Test - public void testQueryRouteWhenTopicNotExist() { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + public void testQueryRouteWhenTopicNotExist() throws Exception { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setEndpoints(Endpoints.newBuilder() @@ -219,17 +222,13 @@ public class RouteServiceTest extends BaseServiceTest { .build()) .build()); - try { - QueryRouteResponse response = future.get(); - assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } + QueryRouteResponse response = future.get(); + assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); } @Test - public void testQueryAssignmentInvalidEndpoints() { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + public void testQueryAssignmentInvalidEndpoints() throws Exception { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic( @@ -239,17 +238,13 @@ public class RouteServiceTest extends BaseServiceTest { ) .build()); - try { - QueryAssignmentResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); - } catch (Exception e) { - assertNull(e); - } + QueryAssignmentResponse response = future.get(); + assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); } @Test - public void testLocalModeQueryAssignment() { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.clientManager); + public void testLocalModeQueryAssignment() throws Exception { + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setEndpoints(Endpoints.newBuilder() @@ -268,20 +263,16 @@ public class RouteServiceTest extends BaseServiceTest { .setClientId("clientId") .build()); - try { - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); } @Test - public void testQueryAssignment() { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.clientManager); + public void testQueryAssignment() throws Exception { + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setEndpoints(Endpoints.newBuilder() @@ -300,15 +291,11 @@ public class RouteServiceTest extends BaseServiceTest { .setClientId("clientId") .build()); - try { - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); - assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); - } catch (Exception e) { - assertNull(e); - } + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); + assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java new file mode 100644 index 0000000000..86831b75d1 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java @@ -0,0 +1,94 @@ +package org.apache.rocketmq.proxy.grpc.service.cluster; + +import apache.rocketmq.v1.EndTransactionRequest; +import apache.rocketmq.v1.EndTransactionResponse; +import apache.rocketmq.v1.PollCommandResponse; +import apache.rocketmq.v1.Resource; +import com.google.rpc.Code; +import io.grpc.Context; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.assertj.core.util.Lists; +import org.junit.Test; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class TransactionServiceTest extends BaseServiceTest { + + private TransactionService transactionService; + @Mock + private ChannelManager channelManager; + + @Override + public void beforeEach() throws Throwable { + transactionService = new TransactionService(this.connectorManager, this.channelManager); + } + + @Test + public void testCheckTransactionState() { + GrpcClientChannel channel = mock(GrpcClientChannel.class); + AtomicReference writeDataRef = new AtomicReference<>(); + + when(channelManager.getClientIdList(anyString())).thenReturn(Lists.newArrayList("clientId")); + when(channelManager.getChannel(anyString(), any())).thenReturn(channel); + doAnswer(mock -> { + writeDataRef.set(mock.getArgument(0)); + return null; + }).when(channel).writeAndFlush(any()); + + TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + "71F99B78B6E261357FA259CCA6456118", 1234, 5678); + transactionService.checkTransactionState(new TransactionStateCheckRequest( + "group", + 1L, + 2L, + "msgId", + transactionId, + createMessageExt("msgId", "msgId") + )); + + assertTrue(writeDataRef.get() instanceof PollCommandResponse); + PollCommandResponse response = (PollCommandResponse) writeDataRef.get(); + assertEquals(transactionId.getProxyTransactionId(), response.getRecoverOrphanedTransactionCommand().getTransactionId()); + } + + @Test + public void testEndTransaction() throws Exception { + AtomicReference headerRef = new AtomicReference<>(); + AtomicReference brokerAddrRef = new AtomicReference<>(); + TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + "71F99B78B6E261357FA259CCA6456118", 1234, 5678); + doAnswer(mock -> { + brokerAddrRef.set(mock.getArgument(0)); + headerRef.set(mock.getArgument(1)); + return null; + }).when(producerClient).endTransaction(anyString(), any(), anyLong()); + + EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setTransactionId(transactionId.getProxyTransactionId()) + .build() + ).get(); + + assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(transactionId.getBrokerTransactionId(), headerRef.get().getTransactionId()); + assertEquals("127.0.0.1:8080", brokerAddrRef.get()); + } +} \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java index d46b76ff70..2739348ab4 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java @@ -49,6 +49,8 @@ import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; import java.security.cert.CertificateException; import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Supplier; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; @@ -124,6 +126,24 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public SendMessageRequest buildSendDelayMessageRequest(String topic, String messageId, int delayLevel) { +// Message message; +// message.getSystemAttribute().getTimedDeliveryCase(); + return SendMessageRequest.newBuilder() + .setMessage(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemAttribute(SystemAttribute.newBuilder() + .setMessageId(messageId) + .setPartitionId(0) + .setDelayLevel(delayLevel) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build(); + } + public ReceiveMessageRequest buildReceiveMessageRequest(String group, String topic) { return ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java index da098271bb..a996584ccc 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java @@ -1,12 +1,17 @@ package org.apache.rocketmq.test.proxy; +import apache.rocketmq.v1.AckMessageResponse; import apache.rocketmq.v1.Address; import apache.rocketmq.v1.AddressScheme; import apache.rocketmq.v1.Endpoints; import apache.rocketmq.v1.MessagingServiceGrpc; import apache.rocketmq.v1.QueryRouteResponse; +import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v1.SendMessageResponse; +import com.google.common.base.Stopwatch; import io.grpc.Channel; import java.net.URL; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; @@ -16,7 +21,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; +import static org.junit.Assert.assertTrue; public class ClusterGrpcTest extends GrpcBaseTest { @@ -61,4 +68,40 @@ public class ClusterGrpcTest extends GrpcBaseTest { .build())); assertQueryRoute(response, brokerControllerList.size()); } + + @Test + public void testSendReceiveMessage() { + String group = "group"; + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(broker1Name, messageId)); + assertSendMessage(sendResponse, messageId); + + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); + assertReceiveMessage(receiveResponse, messageId); + String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); + assertAck(ackMessageResponse); + } + + @Test + public void testSendReceiveDelayMessage() { + String group = "group"; + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendDelayMessageRequest(broker1Name, messageId, 2)); + assertSendMessage(sendResponse, messageId); + + Stopwatch stopwatch = Stopwatch.createStarted(); + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(10, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); + long rcvTime = stopwatch.elapsed(TimeUnit.SECONDS); + assertTrue(Math.abs(rcvTime - 5) < 2); + + assertReceiveMessage(receiveResponse, messageId); + String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); + assertAck(ackMessageResponse); + } + + } From 79fcc9aea2ffdd7b3b5c63ea3f1301ceeb048653 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 25 Mar 2022 17:00:54 +0800 Subject: [PATCH 070/338] [ISSUE #3949] add test cases --- .../rocketmq/proxy/connector/ForwardProducer.java | 1 - .../proxy/grpc/GrpcMessagingProcessor.java | 5 ++--- .../grpc/adapter/channel/GrpcClientChannel.java | 2 +- .../grpc/service/cluster/ConsumerService.java | 1 + .../grpc/service/cluster/PullMessageService.java | 1 - .../grpc/service/cluster/TransactionService.java | 1 + ...viceTest.java => ForwardClientServiceTest.java} | 14 +++++++------- .../grpc/service/cluster/RouteServiceTest.java | 1 - 8 files changed, 12 insertions(+), 14 deletions(-) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/{ClientServiceTest.java => ForwardClientServiceTest.java} (93%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 18b33d1799..3ba34a6406 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -29,7 +29,6 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ForwardProducer extends AbstractForwardClient { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index 08414c5fbf..bb947e9320 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -59,10 +59,9 @@ import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.common.ProxyException; -import org.apache.rocketmq.proxy.grpc.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.common.ResponseWriter; import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index b42d10728a..6a3fcb045d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -71,7 +71,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollCommandResponseManager manager + PollResponseManager manager ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 7d8c58d7ad..78c5d77736 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -46,6 +46,7 @@ import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index caa870efd6..4193609f94 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -40,7 +40,6 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index 1317490bc3..f0f730f17e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -39,6 +39,7 @@ import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java similarity index 93% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java index a099e25923..aadad7a29e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java @@ -23,18 +23,18 @@ import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.common.PollCommandResponseManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; import static org.junit.Assert.*; -public class ClientServiceTest extends BaseServiceTest { +public class ForwardClientServiceTest extends BaseServiceTest { private ChannelManager channelManager = new ChannelManager(); - private PollCommandResponseManager pollCommandResponseManager = new PollCommandResponseManager(); + private PollResponseManager pollResponseManager = new PollResponseManager(); @Override public void beforeEach() throws Throwable { @@ -43,11 +43,11 @@ public class ClientServiceTest extends BaseServiceTest { @Test public void testProducerHeartbeat() { - ClientService clientService = new ClientService( + ForwardClientService clientService = new ForwardClientService( this.connectorManager, Executors.newSingleThreadScheduledExecutor(), this.channelManager, - this.pollCommandResponseManager); + this.pollResponseManager); Metadata metadata = new Metadata(); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); @@ -79,11 +79,11 @@ public class ClientServiceTest extends BaseServiceTest { @Test public void testConsumerHeartbeat() { - ClientService clientService = new ClientService( + ForwardClientService clientService = new ForwardClientService( this.connectorManager, Executors.newSingleThreadScheduledExecutor(), this.channelManager, - this.pollCommandResponseManager); + this.pollResponseManager); List subscriptionEntryList = new ArrayList<>(); subscriptionEntryList.add(SubscriptionEntry.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index 65a89b6888..ba059db95f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -43,7 +43,6 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.grpc.common.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; From 5288501515b15bdbf6d4e72254d9856d5c843ea0 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 25 Mar 2022 17:59:50 +0800 Subject: [PATCH 071/338] [ISSUE #3949] Do some refactor work. --- .../apache/rocketmq/proxy/ProxyStartup.java | 6 +- .../proxy/connector/DefaultForwardClient.java | 14 ++ .../proxy/connector/ForwardProducer.java | 22 +++- .../proxy/connector/ForwardReadConsumer.java | 19 ++- .../proxy/connector/ForwardWriteConsumer.java | 21 ++- .../connector/route/MessageQueueSelector.java | 8 +- .../route/SelectableMessageQueue.java | 2 +- .../proxy/grpc/adapter/GrpcConverter.java | 13 ++ .../proxy/grpc/service/LocalGrpcService.java | 29 ++--- .../grpc/service/cluster/BaseService.java | 9 ++ .../grpc/service/cluster/ConsumerService.java | 122 +++++++++--------- .../cluster/DefaultWriteQueueSelector.java | 26 ++-- .../grpc/service/cluster/ProducerService.java | 55 ++++---- .../service/cluster/PullMessageService.java | 61 ++++----- .../grpc/service/cluster/RouteService.java | 18 ++- .../service/cluster/TransactionService.java | 14 +- 16 files changed, 243 insertions(+), 196 deletions(-) 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 ccacf81d84..4ed9941442 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -58,15 +58,17 @@ public class ProxyStartup { // init thread pool monitor for proxy. initThreadPoolMonitor(); - // create and start grpcServer + // create grpcServer GrpcServer grpcServer = createGrpcServer(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); - // health check server + // create health check server final HealthCheckServer healthCheckServer = new HealthCheckServer(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(healthCheckServer); + // start servers one by one. PROXY_START_AND_SHUTDOWN.start(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { LOGGER.info("try to shutdown server"); try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 43d7bbafd9..711033ae6b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -22,6 +22,7 @@ import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.remoting.exception.RemotingException; @@ -59,6 +60,10 @@ public class DefaultForwardClient extends AbstractForwardClient { return this.getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } + public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId) { + return this.getMaxOffset(brokerAddr, topic, queueId, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture getMaxOffset( String brokerAddr, String topic, @@ -68,6 +73,15 @@ public class DefaultForwardClient extends AbstractForwardClient { return this.getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); } + public CompletableFuture searchOffset( + String brokerAddr, + String topic, + int queueId, + long timestamp + ) { + return this.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture searchOffset( String brokerAddr, String topic, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 3ba34a6406..3752fd6f4c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -26,6 +26,7 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; @@ -52,18 +53,21 @@ public class ForwardProducer extends AbstractForwardClient { return clientFactory.getTransactionalProducer(name, threadCount); } - public CompletableFuture heartBeat(String heartbeatAddr, HeartbeatData heartbeatData, long timeout) throws Exception { return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); } public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { - this.getClient().endTransactionOneway( - brokerAddr, - requestHeader, - "end transaction from rmq proxy", - timeoutMillis - ); + this.getClient().endTransactionOneway(brokerAddr, requestHeader, "end transaction from rmq proxy", timeoutMillis); + } + + public CompletableFuture sendMessage( + String address, + String brokerName, + Message msg, + SendMessageRequestHeader requestHeader + ) { + return this.sendMessage(address, brokerName, msg, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture sendMessage( @@ -84,6 +88,10 @@ public class ForwardProducer extends AbstractForwardClient { }); } + public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { + return this.sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { return this.getClient().sendMessageBack(brokerAddr, requestHeader, timeoutMillis); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 869aeffc14..25e15c1397 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -22,8 +22,9 @@ import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; public class ForwardReadConsumer extends AbstractForwardClient { @@ -46,13 +47,21 @@ public class ForwardReadConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - public CompletableFuture popMessage(String address, String brokerName, PopMessageRequestHeader requestHeader, - long timeoutMillis) { - return getClient().popMessage(address, brokerName, requestHeader, timeoutMillis); + public CompletableFuture popMessage( + String address, + String brokerName, + PopMessageRequestHeader requestHeader, + long timeoutMillis + ) { + return this.getClient().popMessage(address, brokerName, requestHeader, timeoutMillis); + } + + public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { + return this.pullMessage(address, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, long timeoutMillis) { - return getClient().pullMessage(address, requestHeader, timeoutMillis); + return this.getClient().pullMessage(address, requestHeader, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 1c0d721cc0..082c8c5963 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -22,8 +22,9 @@ import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; import org.apache.rocketmq.remoting.exception.RemotingException; public class ForwardWriteConsumer extends AbstractForwardClient { @@ -47,12 +48,24 @@ public class ForwardWriteConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } + public CompletableFuture ackMessage(String address, AckMessageRequestHeader requestHeader) { + return this.ackMessage(address, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture ackMessage( String address, AckMessageRequestHeader requestHeader, long timeoutMillis ) { - return getClient().ackMessage(address, requestHeader, timeoutMillis); + return this.getClient().ackMessage(address, requestHeader, timeoutMillis); + } + + public CompletableFuture changeInvisibleTimeAsync( + String address, + String brokerName, + ChangeInvisibleTimeRequestHeader requestHeader + ) { + return this.changeInvisibleTimeAsync(address, brokerName, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture changeInvisibleTimeAsync( @@ -61,7 +74,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis ) { - return getClient().changeInvisibleTimeAsync(address, brokerName, requestHeader, timeoutMillis); + return this.getClient().changeInvisibleTimeAsync(address, brokerName, requestHeader, timeoutMillis); } public void updateConsumerOffsetOneWay( @@ -69,6 +82,6 @@ public class ForwardWriteConsumer extends AbstractForwardClient { UpdateConsumerOffsetRequestHeader header, long timeoutMillis ) throws RemotingException, InterruptedException { - getClient().updateConsumerOffsetOneWay(brokerAddr, header, timeoutMillis); + this.getClient().updateConsumerOffsetOneWay(brokerAddr, header, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java index 66be2134ff..eff85b1472 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java @@ -153,10 +153,10 @@ public class MessageQueueSelector { } public final SelectableMessageQueue selectOne(String brokerName, int queueId) { - for (SelectableMessageQueue addressableMessageQueue : queues) { - String queueBrokerName = addressableMessageQueue.getBrokerName(); - if (queueBrokerName.equals(brokerName) && addressableMessageQueue.getQueueId() == queueId) { - return addressableMessageQueue; + for (SelectableMessageQueue targetMessageQueue : queues) { + String queueBrokerName = targetMessageQueue.getBrokerName(); + if (queueBrokerName.equals(brokerName) && targetMessageQueue.getQueueId() == queueId) { + return targetMessageQueue; } } return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java index f7b196629d..78a388214d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java @@ -72,7 +72,7 @@ public class SelectableMessageQueue implements Comparable receiveMessage(Context ctx, ReceiveMessageRequest request) { - long timeRemaining = Context.current() - .getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } + long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -392,13 +385,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - long timeRemaining = Context.current() - .getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } + long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index 2c7bb94d3d..61857f4bf9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -16,11 +16,14 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; +import apache.rocketmq.v1.FilterExpression; +import apache.rocketmq.v1.Resource; import com.google.rpc.Code; import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; public class BaseService { @@ -49,4 +52,10 @@ public class BaseService { } return addr; } + + protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { + // for checking filterExpression. + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcConverter.buildSubscriptionData(topicName, filterExpression); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 78c5d77736..c82d658b45 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -25,6 +25,9 @@ import apache.rocketmq.v1.ReceiveMessageRequest; import apache.rocketmq.v1.ReceiveMessageResponse; import com.google.rpc.Code; import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; @@ -37,38 +40,33 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.utils.FilterUtils; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { - + private final DelayPolicy delayPolicy; private final ForwardReadConsumer readConsumer; private final ForwardWriteConsumer writeConsumer; + /** + * For sending messages back to broker. + */ private final ForwardProducer producer; private volatile ReadQueueSelector readQueueSelector; - private volatile ResponseHook receiveMessageHook = null; - private volatile ResponseHook ackNoMatchedMessageHook = null; - private volatile ResponseHook ackMessageHook = null; - private volatile ResponseHook nackMessageHook = null; - - private final DelayPolicy delayPolicy; + private volatile ResponseHook receiveMessageHook; + private volatile ResponseHook ackNoMatchedMessageHook; + private volatile ResponseHook ackMessageHook; + private volatile ResponseHook nackMessageHook; public ConsumerService(ConnectorManager connectorManager) { super(connectorManager); @@ -82,13 +80,15 @@ public class ConsumerService extends BaseService { public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); + // register hook. future.whenComplete((response, throwable) -> { if (receiveMessageHook != null) { receiveMessageHook.beforeResponse(ctx, request, response, throwable); } }); + try { - PopMessageRequestHeader requestHeader = this.convertToPopMessageRequestHeader(ctx, request); + PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); if (messageQueue == null) { @@ -118,27 +118,19 @@ public class ConsumerService extends BaseService { return future; } - protected PopMessageRequestHeader convertToPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { - // check filterExpression is correct or not - GrpcConverter.buildSubscriptionData(GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); - - long timeRemaining = ctx.getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - - return GrpcConverter.buildPopMessageRequestHeader(request, pollTime); + protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { + checkSubscriptionData(request.getPartition().getTopic(), request.getFilterExpression()); + return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( - GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); PopStatus status = result.getPopStatus(); switch (status) { case FOUND: - break; + return ReceiveMessageResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .addAllMessages(checkAndGetMessagesFromPopResult(ctx, request, result)) + .build(); case POLLING_FULL: return ReceiveMessageResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.RESOURCE_EXHAUSTED, "polling full")) @@ -150,6 +142,11 @@ public class ConsumerService extends BaseService { .setCommon(ResponseBuilder.buildCommon(Code.OK, "no new message")) .build(); } + } + + protected List checkAndGetMessagesFromPopResult(Context ctx, ReceiveMessageRequest request, PopResult result) { + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); List messages = new ArrayList<>(); for (MessageExt messageExt : result.getMsgFoundList()) { @@ -160,14 +157,12 @@ public class ConsumerService extends BaseService { messages.add(GrpcConverter.buildMessage(messageExt)); } - return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .addAllMessages(messages) - .build(); + return messages; } protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { CompletableFuture future = new CompletableFuture<>(); + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); try { ReceiptHandle handle = ReceiptHandle.create(messageExt); @@ -181,15 +176,17 @@ public class ConsumerService extends BaseService { ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); ackMessageRequestHeader.setOffset(handle.getOffset()); - future = this.writeConsumer.ackMessage(brokerAddr, ackMessageRequestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + future = this.writeConsumer.ackMessage(brokerAddr, ackMessageRequestHeader); } catch (Throwable t) { future.completeExceptionally(t); } + future.whenComplete((ackResult, throwable) -> { if (ackNoMatchedMessageHook != null) { ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); } }); + } public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { @@ -199,31 +196,32 @@ public class ConsumerService extends BaseService { ackMessageHook.beforeResponse(ctx, request, response, throwable); } }); + try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - AckMessageRequestHeader requestHeader = this.convertToAckMessageRequestHeader(ctx, request); - CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request); + CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader); ackResultFuture - .thenAccept(result -> { - try { - future.complete(convertToAckMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { + .thenAccept(result -> { + try { + future.complete(convertToAckMessageResponse(ctx, request, result)); + } catch (Throwable throwable) { future.completeExceptionally(throwable); - return null; - }); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); } catch (Throwable t) { future.completeExceptionally(t); } return future; } - protected AckMessageRequestHeader convertToAckMessageRequestHeader(Context ctx, AckMessageRequest request) { + protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request) { return GrpcConverter.buildAckMessageRequestHeader(request); } @@ -252,8 +250,9 @@ public class ConsumerService extends BaseService { if (request.getDeliveryAttempt() >= request.getMaxDeliveryAttempts()) { CompletableFuture resultFuture = this.producer.sendMessageBack( brokerAddr, - this.convertToConsumerSendMsgBackToDLQRequestHeader(ctx, request), - ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request) + ); + resultFuture .thenAccept(result -> { try { @@ -267,9 +266,8 @@ public class ConsumerService extends BaseService { return null; }); } else { - ChangeInvisibleTimeRequestHeader requestHeader = this.convertToChangeInvisibleTimeRequestHeader(ctx, request); - CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader, - ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); + CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); resultFuture .thenAccept(result -> { try { @@ -289,11 +287,11 @@ public class ConsumerService extends BaseService { return future; } - protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { + return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } - protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request) { + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request) { return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request); } @@ -318,23 +316,19 @@ public class ConsumerService extends BaseService { this.readQueueSelector = readQueueSelector; } - public void setReceiveMessageHook( - ResponseHook receiveMessageHook) { + public void setReceiveMessageHook(ResponseHook receiveMessageHook) { this.receiveMessageHook = receiveMessageHook; } - public void setAckNoMatchedMessageHook( - ResponseHook ackNoMatchedMessageHook) { + public void setAckNoMatchedMessageHook(ResponseHook ackNoMatchedMessageHook) { this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; } - public void setAckMessageHook( - ResponseHook ackMessageHook) { + public void setAckMessageHook(ResponseHook ackMessageHook) { this.ackMessageHook = ackMessageHook; } - public void setNackMessageHook( - ResponseHook nackMessageHook) { + public void setNackMessageHook(ResponseHook nackMessageHook) { this.nackMessageHook = nackMessageHook; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java index 1cc9ba7bc6..19948a0c5a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java @@ -27,8 +27,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DefaultWriteQueueSelector implements WriteQueueSelector { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); - private static final Logger log = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); protected final TopicRouteCache topicRouteCache; public DefaultWriteQueueSelector(TopicRouteCache topicRouteCache) { @@ -36,9 +36,12 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { } @Override - public SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, + public SelectableMessageQueue selectQueue( + Context ctx, + SendMessageRequest request, SendMessageRequestHeader requestHeader, - org.apache.rocketmq.common.message.Message message) { + org.apache.rocketmq.common.message.Message message + ) { try { String topic = requestHeader.getTopic(); String brokerName = ""; @@ -47,19 +50,19 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { } Integer queueId = requestHeader.getQueueId(); String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); - SelectableMessageQueue addressableMessageQueue; - if (!StringUtils.isBlank(brokerName) && queueId != null) { + SelectableMessageQueue targetMessageQueue; + if (StringUtils.isNotBlank(brokerName) && queueId != null) { // Grpc client sendSelect situation - addressableMessageQueue = selectTargetQueue(topic, brokerName, queueId); + targetMessageQueue = selectTargetQueue(topic, brokerName, queueId); } else if (shardingKey != null) { // With shardingKey - addressableMessageQueue = selectOrderQueue(topic, shardingKey); + targetMessageQueue = selectOrderQueue(topic, shardingKey); } else { - addressableMessageQueue = selectNormalQueue(topic); + targetMessageQueue = selectNormalQueue(topic); } - return addressableMessageQueue; + return targetMessageQueue; } catch (Exception e) { - log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); + LOGGER.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); return null; } } @@ -68,8 +71,7 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { return this.topicRouteCache.selectOneWriteQueue(topic, null); } - protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, - int queueId) throws Exception { + protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { return this.topicRouteCache.selectOneWriteQueue(topic, brokerName, queueId); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index e924e28855..1e23ce167d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -31,8 +31,8 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; @@ -42,12 +42,15 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerService extends BaseService { + private final ForwardProducer producer; private volatile WriteQueueSelector writeQueueSelector; - private volatile ResponseHook sendMessageHook = null; - private volatile ResponseHook forwardMessageToDLQHook = null; + private volatile ResponseHook sendMessageHook; + private volatile ResponseHook forwardMessageToDLQHook; + public ProducerService(ConnectorManager connectorManager) { super(connectorManager); + this.producer = connectorManager.getForwardProducer(); writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); } @@ -73,23 +76,24 @@ public class ProducerService extends BaseService { }); try { - Pair requestPair = this.convertSendMessageRequest(ctx, request); + Pair requestPair = this.buildSendMessageRequest(ctx, request); SendMessageRequestHeader requestHeader = requestPair.getLeft(); org.apache.rocketmq.common.message.Message message = requestPair.getRight(); - SelectableMessageQueue addressableMessageQueue = writeQueueSelector.selectQueue(ctx, request, requestHeader, message); + SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); - if (addressableMessageQueue == null) { - throw new ProxyException(Code.NOT_FOUND, "no writeable topic route for topic " + topic); + if (selectableMessageQueue == null) { + throw new ProxyException(Code.NOT_FOUND, "no writeable topic route for topic: " + topic); } - CompletableFuture sendResultCompletableFuture = this.connectorManager.getForwardProducer().sendMessage( - addressableMessageQueue.getBrokerAddr(), - addressableMessageQueue.getBrokerName(), + // send message to broker. + CompletableFuture sendResultCompletableFuture = this.producer.sendMessage( + selectableMessageQueue.getBrokerAddr(), + selectableMessageQueue.getBrokerName(), message, - requestHeader, - ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT + requestHeader ); + sendResultCompletableFuture .thenAccept(result -> { try { @@ -108,20 +112,21 @@ public class ProducerService extends BaseService { return future; } - protected Pair convertSendMessageRequest( + protected Pair buildSendMessageRequest( Context ctx, SendMessageRequest request) { - return Pair.of(GrpcConverter.buildSendMessageRequestHeader(request), GrpcConverter.buildMessage(request.getMessage())); + SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request); + org.apache.rocketmq.common.message.Message message = GrpcConverter.buildMessage(request.getMessage()); + return Pair.of(requestHeader, message); } - protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, - SendResult sendResult) { - if (sendResult.getSendStatus() != SendStatus.SEND_OK) { + protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult result) { + if (result.getSendStatus() != SendStatus.SEND_OK) { return SendMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + sendResult.getSendStatus())) + .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + result.getSendStatus())) .build(); } - if (StringUtils.isNotBlank(sendResult.getTransactionId())) { + if (StringUtils.isNotBlank(result.getTransactionId())) { Message message = request.getMessage(); String group = GrpcConverter.wrapResourceWithNamespace(message.getSystemAttribute().getProducerGroup()); String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); @@ -130,8 +135,8 @@ public class ProducerService extends BaseService { return SendMessageResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .setMessageId(StringUtils.defaultString(sendResult.getMsgId())) - .setTransactionId(StringUtils.defaultString(sendResult.getTransactionId())) + .setMessageId(StringUtils.defaultString(result.getMsgId())) + .setTransactionId(StringUtils.defaultString(result.getTransactionId())) // use "" if transactionID is null. .build(); } @@ -143,12 +148,12 @@ public class ProducerService extends BaseService { forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); } }); + try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - ConsumerSendMsgBackRequestHeader requestHeader = this.convertToConsumerSendMsgBackRequestHeader(ctx, request); - CompletableFuture resultFuture = this.connectorManager.getForwardProducer() - .sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + ConsumerSendMsgBackRequestHeader requestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); + CompletableFuture resultFuture = this.producer.sendMessageBack(brokerAddr, requestHeader); resultFuture .thenAccept(result -> future.complete( @@ -167,7 +172,7 @@ public class ProducerService extends BaseService { return future; } - protected ConsumerSendMsgBackRequestHeader convertToConsumerSendMsgBackRequestHeader(Context ctx, + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index 4193609f94..b3fc812089 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -20,7 +20,6 @@ import apache.rocketmq.v1.Message; import apache.rocketmq.v1.Partition; import apache.rocketmq.v1.PullMessageRequest; import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryOffsetPolicy; import apache.rocketmq.v1.QueryOffsetRequest; import apache.rocketmq.v1.QueryOffsetResponse; import com.google.protobuf.util.Timestamps; @@ -28,32 +27,31 @@ import com.google.rpc.Code; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.utils.FilterUtils; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; +import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class PullMessageService extends BaseService { - private final DefaultForwardClient defaultForwardClient; + private final DefaultForwardClient forwardClient; + private final ForwardReadConsumer readConsumer; - private volatile ResponseHook queryOffsetHook = null; - - private volatile ResponseHook pullMessageHook = null; + private volatile ResponseHook queryOffsetHook; + private volatile ResponseHook pullMessageHook; public PullMessageService(ConnectorManager connectorManager) { super(connectorManager); - this.defaultForwardClient = connectorManager.getDefaultForwardClient(); + this.forwardClient = connectorManager.getDefaultForwardClient(); + this.readConsumer = connectorManager.getForwardReadConsumer(); } public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { @@ -63,24 +61,28 @@ public class PullMessageService extends BaseService { queryOffsetHook.beforeResponse(ctx, request, response, throwable); } }); + try { Partition partition = request.getPartition(); String topic = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); - String brokerName = partition.getBroker().getName(); int queueId = partition.getId(); + CompletableFuture offsetFuture; - if (request.getPolicy() == QueryOffsetPolicy.BEGINNING) { - offsetFuture = CompletableFuture.completedFuture(0L); - } else if (request.getPolicy() == QueryOffsetPolicy.END) { - String brokerAddr = this.getBrokerAddr(ctx, brokerName); - offsetFuture = this.defaultForwardClient.getMaxOffset(brokerAddr, topic, queueId, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); - } else { - long timestamp = Timestamps.toMillis(request.getTimePoint()); - String brokerAddr = this.getBrokerAddr(ctx, brokerName); - offsetFuture = this.defaultForwardClient.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + switch (request.getPolicy()) { + case BEGINNING: + offsetFuture = CompletableFuture.completedFuture(0L); + break; + case END: + offsetFuture = this.forwardClient.getMaxOffset(this.getBrokerAddr(ctx, brokerName), topic, queueId); + break; + default: + long timestamp = Timestamps.toMillis(request.getTimePoint()); + offsetFuture = this.forwardClient.searchOffset(this.getBrokerAddr(ctx, brokerName), topic, queueId, timestamp); } - offsetFuture.thenAccept(result -> future.complete( + + offsetFuture + .thenAccept(result -> future.complete( QueryOffsetResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .setOffset(result) @@ -104,13 +106,12 @@ public class PullMessageService extends BaseService { }); try { - PullMessageRequestHeader requestHeader = this.convertToPullMessageRequestHeader(ctx, request); + PullMessageRequestHeader requestHeader = this.buildPullMessageRequestHeader(ctx, request); String brokerName = request.getPartition().getBroker().getName(); String brokerAddr = this.getBrokerAddr(ctx, brokerName); - CompletableFuture pullResultFuture = this.connectorManager.getForwardReadConsumer() - .pullMessage(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + CompletableFuture pullResultFuture = this.readConsumer.pullMessage(brokerAddr, requestHeader); pullResultFuture .thenAccept(pullResult -> { try { @@ -130,17 +131,9 @@ public class PullMessageService extends BaseService { return future; } - protected PullMessageRequestHeader convertToPullMessageRequestHeader(Context ctx, PullMessageRequest request) { - // check filterExpression is correct or not - GrpcConverter.buildSubscriptionData(GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); - - long timeRemaining = ctx.getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - return GrpcConverter.buildPullMessageRequestHeader(request, pollTime); + protected PullMessageRequestHeader buildPullMessageRequestHeader(Context ctx, PullMessageRequest request) { + checkSubscriptionData(request.getPartition().getTopic(), request.getFilterExpression()); + return GrpcConverter.buildPullMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); } protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 7ec10d6b5a..5b48a15d4a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -56,11 +56,11 @@ public class RouteService extends BaseService { private final ProxyMode mode; private volatile ParameterConverter queryRouteEndpointConverter; - private volatile ResponseHook queryRouteHook = null; + private volatile ResponseHook queryRouteHook; private volatile ParameterConverter queryAssignmentEndpointConverter; private volatile AssignmentQueueSelector assignmentQueueSelector; - private volatile ResponseHook queryAssignmentHook = null; + private volatile ResponseHook queryAssignmentHook; public RouteService(ProxyMode mode, ConnectorManager connectorManager) { super(connectorManager); @@ -79,8 +79,7 @@ public class RouteService extends BaseService { this.queryRouteHook = queryRouteHook; } - public void setQueryAssignmentEndpointConverter( - ParameterConverter queryAssignmentEndpointConverter) { + public void setQueryAssignmentEndpointConverter(ParameterConverter queryAssignmentEndpointConverter) { this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; } @@ -88,8 +87,7 @@ public class RouteService extends BaseService { this.assignmentQueueSelector = assignmentQueueSelector; } - public void setQueryAssignmentHook( - ResponseHook queryAssignmentHook) { + public void setQueryAssignmentHook(ResponseHook queryAssignmentHook) { this.queryAssignmentHook = queryAssignmentHook; } @@ -102,8 +100,8 @@ public class RouteService extends BaseService { }); try { - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() - .getMessageQueue(GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); List brokerDataList = topicRouteData.getBrokerDatas(); @@ -217,8 +215,8 @@ public class RouteService extends BaseService { List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); if (ProxyMode.isLocalMode(mode)) { - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache() - .getMessageQueue(GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); for (SelectableMessageQueue messageQueue : messageQueueList) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index f0f730f17e..bcc4796d8f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -46,8 +46,8 @@ public class TransactionService extends BaseService implements TransactionStateC private final ChannelManager channelManager; private final ForwardProducer forwardProducer; - private volatile ResponseHook checkTransactionStateHook = null; - private volatile ResponseHook endTransactionHook = null; + private volatile ResponseHook checkTransactionStateHook; + private volatile ResponseHook endTransactionHook; public TransactionService(ConnectorManager connectorManager, ChannelManager channelManager) { super(connectorManager); @@ -63,11 +63,11 @@ public class TransactionService extends BaseService implements TransactionStateC if (CollectionUtils.isEmpty(clientIdList)) { return; } + String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); - GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); - String transactionId = checkData.getTransactionId().getProxyTransactionId(); + String transactionId = checkData.getTransactionId().getProxyTransactionId(); Message message = GrpcConverter.buildMessage(checkData.getMessageExt()); PollCommandResponse response = PollCommandResponse.newBuilder() .setRecoverOrphanedTransactionCommand( @@ -76,6 +76,7 @@ public class TransactionService extends BaseService implements TransactionStateC .setTransactionId(transactionId) .build() ).build(); + channel.writeAndFlush(response); if (this.checkTransactionStateHook != null) { this.checkTransactionStateHook.beforeResponse(ctx, checkData, response, null); @@ -97,10 +98,9 @@ public class TransactionService extends BaseService implements TransactionStateC try { TransactionId handle = TransactionId.decode(request.getTransactionId()); + String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); - this.forwardProducer.endTransaction( - RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()), - requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + this.forwardProducer.endTransaction(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); future.complete(EndTransactionResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .build()); From 29084f87d4215683a5b41dee490da9ccdc2ccd5d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 25 Mar 2022 20:29:22 +0800 Subject: [PATCH 072/338] [ISSUE #3949] Sort code for rebase --- .../rocketmq/broker/BrokerController.java | 4 +++ .../rocketmq/proxy/grpc/GrpcServer.java | 2 +- .../proxy/grpc/service/LocalGrpcService.java | 28 +++++++---------- .../service/cluster/ForwardClientService.java | 10 ++++-- .../grpc/service/LocalGrpcServiceTest.java | 31 +++++++++---------- 5 files changed, 39 insertions(+), 36 deletions(-) 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 7bf9cdcd9c..ded926f898 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java @@ -2046,6 +2046,10 @@ public class BrokerController { return assignmentManager; } + public ClientManageProcessor getClientManageProcessor() { + return clientManageProcessor; + } + public SendMessageProcessor getSendMessageProcessor() { return sendMessageProcessor; } 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 dc36a5e13f..0627e08fb1 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 @@ -31,9 +31,9 @@ import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.acl.AccessValidator; -import org.apache.rocketmq.broker.util.ServiceProvider; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.common.utils.ServiceProvider; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index bf3d497edb..8b90940dac 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -204,12 +204,12 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo = new InvocationContext<>(request, future); channel.registerInvocationContext(command.getOpaque(), context); try { - CompletableFuture processorFuture = brokerController.getSendMessageProcessor() - .asyncProcessRequest(channelHandlerContext, command); - processorFuture.thenAccept(r -> { - handler.handle(r, context); + RemotingCommand response = brokerController.getSendMessageProcessor() + .processRequest(channelHandlerContext, command); + if (response != null) { + handler.handle(response, context); channel.eraseInvocationContext(command.getOpaque()); - }); + } } catch (final Exception e) { LOGGER.error("Failed to process send message command", e); channel.eraseInvocationContext(command.getOpaque()); @@ -313,18 +313,12 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo CompletableFuture future = new CompletableFuture<>(); try { - CompletableFuture processorFuture = brokerController.getSendMessageProcessor() - .asyncProcessRequest(channelHandlerContext, command); - processorFuture.thenAccept(r -> { - ForwardMessageToDeadLetterQueueResponse.Builder builder = ForwardMessageToDeadLetterQueueResponse.newBuilder(); - if (null != r) { - builder.setCommon(ResponseBuilder.buildCommon(r.getCode(), r.getRemark())); - } else { - builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); - } - ForwardMessageToDeadLetterQueueResponse response = builder.build(); - future.complete(response); - }); + RemotingCommand response = brokerController.getSendMessageProcessor() + .processRequest(channelHandlerContext, command); + + future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setCommon(ResponseBuilder.buildCommon(response.getCode(), response.getRemark())) + .build()); } catch (Exception e) { LOGGER.error("Exception raised when forwardMessageToDeadLetterQueue", e); future.completeExceptionally(e); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index eb8144e34f..1b68c1c1ac 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -29,6 +29,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; @@ -65,8 +67,12 @@ public class ForwardClientService extends BaseService { this.channelManager = channelManager; this.pollCommandResponseManager = pollCommandResponseManager; - this.consumerManager = new ConsumerManager((event, group, args) -> { - // nothing to do in handler. + this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { + @Override public void handle(ConsumerGroupEvent event, String group, Object... args) { + } + + @Override public void shutdown() { + } }); this.producerManager = new ProducerManager(); this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 899cc3cebc..6a252d2ca8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -82,6 +82,7 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.store.MessageStore; +import org.apache.rocketmq.store.config.MessageStoreConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -113,6 +114,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); Mockito.when(brokerControllerMock.getPullMessageProcessor()).thenReturn(pullMessageProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); + Mockito.when(brokerControllerMock.getMessageStoreConfig()).thenReturn(new MessageStoreConfig()); localGrpcService = new LocalGrpcService(brokerControllerMock); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); @@ -168,9 +170,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { public void testSendMessageError() throws Exception { String remark = "store putMessage return null"; RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SYSTEM_ERROR, remark); - CompletableFuture future = CompletableFuture.completedFuture(response); - Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(future); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); SendMessageRequest request = SendMessageRequest.newBuilder() .setMessage(Message.newBuilder() .setSystemAttribute(SystemAttribute.newBuilder() @@ -188,9 +189,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testSendMessageWriteAndFlush() throws Exception { - CompletableFuture future = CompletableFuture.completedFuture(null); - Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(future); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(null); SendMessageRequest request = SendMessageRequest.newBuilder() .setMessage(Message.newBuilder() .setSystemAttribute(SystemAttribute.newBuilder() @@ -206,7 +206,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testSendMessageWithException() throws Exception { - Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenThrow(new RemotingCommandException("test")); SendMessageRequest request = SendMessageRequest.newBuilder() .setMessage(Message.newBuilder() @@ -256,9 +256,9 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.receiveMessage( Context.current() .withValue(InterceptorConstants.METADATA, metadata) + .attach() .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))) - .attach(), request); + new ThreadFactoryImpl("test"))), request); ReceiveMessageResponse r = grpcFuture.get(); assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); assertThat(r.getMessagesCount()).isEqualTo(1); @@ -275,9 +275,9 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.receiveMessage( Context.current() .withValue(InterceptorConstants.METADATA, metadata) + .attach() .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))) - .attach(), request); + new ThreadFactoryImpl("test"))), request); assertThat(grpcFuture.isDone()).isFalse(); } @@ -345,11 +345,10 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testForwardMessageToDeadLetterQueue() throws Exception { RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - CompletableFuture future = CompletableFuture.completedFuture(response); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); - Mockito.when(sendMessageProcessorMock.asyncProcessRequest(Mockito.any(ChannelHandlerContext.class), + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.argThat(argument -> argument.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK))) - .thenReturn(future); + .thenReturn(response); ForwardMessageToDeadLetterQueueRequest request = ForwardMessageToDeadLetterQueueRequest.newBuilder() .setReceiptHandle(ReceiptHandle.builder() .startOffset(0L) @@ -557,9 +556,9 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.pullMessage( Context.current() .withValue(InterceptorConstants.METADATA, metadata) + .attach() .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))) - .attach(), request); + new ThreadFactoryImpl("test"))), request); PullMessageResponse r = grpcFuture.get(); assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); assertThat(r.getMessagesCount()).isEqualTo(1); From 1976cc44cab75935fee1b90b1bf5a343c88a3426 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 25 Mar 2022 20:47:19 +0800 Subject: [PATCH 073/338] [ISSUE #3949] use log instead of LOGGER & pass unit tests. --- .../apache/rocketmq/proxy/ProxyStartup.java | 11 +++++----- .../proxy/channel/ChannelManager.java | 6 +++--- .../proxy/channel/InvocationChannel.java | 4 ++-- .../rocketmq/proxy/channel/SimpleChannel.java | 3 +-- .../rocketmq/proxy/config/Configuration.java | 6 +++--- .../proxy/connector/ForwardReadConsumer.java | 5 +++++ .../factory/AbstractClientFactory.java | 4 ++-- .../connector/route/TopicRouteCache.java | 1 - .../connector/route/TopicRouteWrapper.java | 4 ++-- .../proxy/grpc/GrpcMessagingProcessor.java | 2 +- .../rocketmq/proxy/grpc/GrpcServer.java | 10 +++++----- .../proxy/grpc/adapter/GrpcConverter.java | 4 ++-- .../proxy/grpc/adapter/ResponseWriter.java | 10 +++++----- .../ReceiveMessageResponseHandler.java | 11 +++++----- .../grpc/service/ClusterGrpcService.java | 2 +- .../proxy/grpc/service/LocalGrpcService.java | 20 +++++++++---------- .../cluster/DefaultWriteQueueSelector.java | 4 ++-- .../service/cluster/ForwardClientService.java | 4 ++-- .../service/cluster/ConsumerServiceTest.java | 11 +++++----- .../service/cluster/ProducerServiceTest.java | 8 ++------ .../cluster/PullMessageServiceTest.java | 11 ++++------ 21 files changed, 69 insertions(+), 72 deletions(-) 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 4ed9941442..7d2640293f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -38,8 +38,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ProxyStartup { - - private static final Logger LOGGER = LoggerFactory.getLogger(ProxyStartup.class); + private static final Logger log = LoggerFactory.getLogger(ProxyStartup.class); private static final ProxyStartAndShutdown PROXY_START_AND_SHUTDOWN = new ProxyStartAndShutdown(); private static class ProxyStartAndShutdown extends AbstractStartAndShutdown { @@ -70,22 +69,22 @@ public class ProxyStartup { PROXY_START_AND_SHUTDOWN.start(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { - LOGGER.info("try to shutdown server"); + log.info("try to shutdown server"); try { PROXY_START_AND_SHUTDOWN.shutdown(); } catch (Exception e) { - LOGGER.error("err when shutdown proxy", e); + log.error("err when shutdown proxy", e); } })); } catch (Exception e) { System.err.println("find a unexpect err." + e); e.printStackTrace(); - LOGGER.error("find a unexpect err.", e); + log.error("find a unexpect err.", e); System.exit(1); } System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); - LOGGER.info(new Date() + "rmq-proxy startup successfully"); + log.info(new Date() + "rmq-proxy startup successfully"); } private static GrpcServer createGrpcServer() throws Exception { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 3719a487c0..3b751aec64 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -37,7 +37,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ChannelManager { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); @@ -55,7 +55,7 @@ public class ChannelManager { public T createChannel(String clientId, Supplier creator, Class clazz) { if (Strings.isNullOrEmpty(clientId)) { - LOGGER.warn("ClientId is unexpected null or empty"); + log.warn("ClientId is unexpected null or empty"); return creator.get(); } @@ -153,7 +153,7 @@ public class ChannelManager { } } } catch (Throwable e) { - LOGGER.error("Unexpected exception", e); + log.error("Unexpected exception", e); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java index 23caa9e8e5..80750f5fb2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -81,12 +81,12 @@ public abstract class InvocationChannel extends SimpleChannel implements C if (entry.getValue().expired(expiredTimeSec)) { iterator.remove(); count++; - LOGGER.debug("An expired request is found, created time-point: {}, Request: {}", + log.debug("An expired request is found, created time-point: {}, Request: {}", entry.getValue().getTimestamp(), entry.getValue().getRequest()); } } if (count > 0) { - LOGGER.warn("[BUG] {} expired in-flight requests is cleaned.", count); + log.warn("[BUG] {} expired in-flight requests is cleaned.", count); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java index a7305e1c92..31b762294d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java @@ -39,8 +39,7 @@ import org.slf4j.LoggerFactory; * @see io.netty.channel.Channel#writeAndFlush */ public class SimpleChannel extends AbstractChannel { - - protected static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + protected static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); protected final String remoteAddress; protected final String localAddress; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java index 9e79532e32..29d14d5aa6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java @@ -25,7 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Configuration { - private final static Logger LOGGER = LoggerFactory.getLogger(Configuration.class); + private final static Logger log = LoggerFactory.getLogger(Configuration.class); private final AtomicReference proxyConfigReference = new AtomicReference<>(); public void init() throws Exception { @@ -43,12 +43,12 @@ public class Configuration { File file = new File(filePath); if (!file.exists()) { - LOGGER.warn("the config file {} not exist", filePath); + log.warn("the config file {} not exist", filePath); return null; } long fileLength = file.length(); if (fileLength <= 0) { - LOGGER.warn("the config file {} length is zero", filePath); + log.warn("the config file {} length is zero", filePath); return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 25e15c1397..37ee10f95c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -47,6 +47,11 @@ public class ForwardReadConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } + public CompletableFuture popMessage(String address, String brokerName, + PopMessageRequestHeader requestHeader) { + return this.popMessage(address, brokerName, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture popMessage( String address, String brokerName, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java index f5d3aa379a..e5ea496c9a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java @@ -25,7 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractClientFactory { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientFactory.class); + private static final Logger log = LoggerFactory.getLogger(AbstractClientFactory.class); protected final ScheduledExecutorService scheduledExecutorService; protected Map cacheTable = new ConcurrentHashMap<>(); @@ -78,7 +78,7 @@ public abstract class AbstractClientFactory { try { this.shutdown(v); } catch (Exception e) { - LOGGER.warn("try to shutdown client err.", e); + log.warn("try to shutdown client err.", e); } }); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index 746f4ad430..b3f62c1a3d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -37,7 +37,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TopicRouteCache { - private static final Logger log = LoggerFactory.getLogger(TopicRouteCache.class); private final LoadingCache topicCache; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java index a08bd3aa52..5b566dbc13 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java @@ -37,13 +37,13 @@ public class TopicRouteWrapper { if (this.topicRouteData.getBrokerDatas() != null) { for (BrokerData brokerData : this.topicRouteData.getBrokerDatas()) { - brokerNameRouteData.put(brokerData.getBrokerName(), brokerData); + this.brokerNameRouteData.put(brokerData.getBrokerName(), brokerData); } } } public String getMasterAddr(String brokerName) { - return brokerNameRouteData.get(brokerName).getBrokerAddrs().get(MixAll.MASTER_ID); + return this.brokerNameRouteData.get(brokerName).getBrokerAddrs().get(MixAll.MASTER_ID); } public String getMasterAddrPrefer(String brokerName) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index bb947e9320..f520cc36be 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -67,7 +67,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final GrpcForwardService grpcForwardService; public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { 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 0627e08fb1..6ebda585a4 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 @@ -44,7 +44,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GrpcServer implements StartAndShutdown { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final io.grpc.Server server; private final ThreadPoolExecutor executor; @@ -68,7 +68,7 @@ public class GrpcServer implements StartAndShutdown { .build(); serverBuilder.sslContext(sslContext); } catch (IOException e) { - LOGGER.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); + log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); throw new RuntimeException("grpc tls set failed: " + e.getMessage()); } @@ -109,7 +109,7 @@ public class GrpcServer implements StartAndShutdown { .intercept(new HeaderInterceptor()) .build(); - LOGGER.info( + log.info( "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", port, tlsKeyPath, tlsCertPath, threadPoolNums, threadPoolQueueCapacity, @@ -122,7 +122,7 @@ public class GrpcServer implements StartAndShutdown { this.grpcForwardService.start(); this.server.start(); - LOGGER.info("grpc server has started"); + log.info("grpc server has started"); } public void shutdown() { @@ -132,7 +132,7 @@ public class GrpcServer implements StartAndShutdown { this.grpcForwardService.shutdown(); - LOGGER.info("grpc server has stopped"); + log.info("grpc server has stopped"); } catch (Exception e) { e.printStackTrace(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java index cac8fcd16b..7199069975 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java @@ -96,7 +96,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GrpcConverter { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); public static String wrapResourceWithNamespace(Resource resource) { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); @@ -143,7 +143,7 @@ public class GrpcConverter { int queueId = partition.getId(); int maxMessageNumbers = request.getBatchSize(); if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { - LOGGER.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", + log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java index 601e509de2..44860e1919 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResponseWriter { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); public static void write(StreamObserver observer, final T response) { if (observer instanceof ServerCallStreamObserver) { @@ -34,11 +34,11 @@ public class ResponseWriter { final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (serverCallStreamObserver.isCancelled()) { - LOGGER.warn("client has cancelled the request. response to write: {}", response); + log.warn("client has cancelled the request. response to write: {}", response); return; } - LOGGER.debug("start to write response. response: {}", response); + log.debug("start to write response. response: {}", response); serverCallStreamObserver.onNext(response); serverCallStreamObserver.onCompleted(); } @@ -52,7 +52,7 @@ public class ResponseWriter { } if (serverCallStreamObserver.isCancelled()) { - LOGGER.warn("Client has cancelled the request. Exception to write", e); + log.warn("Client has cancelled the request. Exception to write", e); return; } @@ -65,7 +65,7 @@ public class ResponseWriter { // } // } - LOGGER.debug("Start to write error response", e); + log.debug("Start to write error response", e); serverCallStreamObserver.onError(e); serverCallStreamObserver.onCompleted(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java index 82b5127067..9684261673 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java @@ -45,9 +45,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ReceiveMessageResponseHandler implements ResponseHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - @Override public void handle(RemotingCommand responseCommand, + @Override + public void handle(RemotingCommand responseCommand, InvocationContext context) { ReceiveMessageRequest request = context.getRequest(); CompletableFuture future = context.getResponse(); @@ -103,7 +104,7 @@ public class ReceiveMessageResponseHandler implements ResponseHandler healthCheck(Context ctx, HealthCheckRequest request) { - LOGGER.trace("Received health check request from client: {}", request.getClientHost()); + log.trace("Received health check request from client: {}", request.getClientHost()); final HealthCheckResponse response = HealthCheckResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) .build(); @@ -211,7 +211,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); } } catch (final Exception e) { - LOGGER.error("Failed to process send message command", e); + log.error("Failed to process send message command", e); channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } @@ -244,7 +244,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); } } catch (Exception e) { - LOGGER.error("Failed to process pop message command", e); + log.error("Failed to process pop message command", e); channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } @@ -272,7 +272,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo AckMessageResponse response = builder.build(); future.complete(response); } catch (Exception e) { - LOGGER.error("Exception raised when ack message", e); + log.error("Exception raised when ack message", e); } return future; } @@ -295,7 +295,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .build(); future.complete(response); } catch (Exception e) { - LOGGER.error("Exception raised while nackMessage", e); + log.error("Exception raised while nackMessage", e); future.completeExceptionally(e); } return future; @@ -320,7 +320,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .setCommon(ResponseBuilder.buildCommon(response.getCode(), response.getRemark())) .build()); } catch (Exception e) { - LOGGER.error("Exception raised when forwardMessageToDeadLetterQueue", e); + log.error("Exception raised when forwardMessageToDeadLetterQueue", e); future.completeExceptionally(e); } return future; @@ -348,7 +348,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo EndTransactionResponse response = builder.build(); future.complete(response); } catch (Exception e) { - LOGGER.error("Exception raised while endTransaction", e); + log.error("Exception raised while endTransaction", e); future.completeExceptionally(e); } return future; @@ -398,7 +398,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); } } catch (Exception e) { - LOGGER.error("Failed to process pull message command", e); + log.error("Failed to process pull message command", e); channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } @@ -535,7 +535,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo future.complete(builder.build()); } catch (Exception e) { - LOGGER.error("Exception raised while changeInvisibleDuration", e); + log.error("Exception raised while changeInvisibleDuration", e); future.completeExceptionally(e); } return future; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java index 19948a0c5a..7d91a8233b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java @@ -27,7 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DefaultWriteQueueSelector implements WriteQueueSelector { - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); + private static final Logger log = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); protected final TopicRouteCache topicRouteCache; @@ -62,7 +62,7 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { } return targetMessageQueue; } catch (Exception e) { - LOGGER.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); + log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); return null; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index 1b68c1c1ac..32e9b76b47 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -45,7 +45,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ForwardClientService extends BaseService { - private static final Logger LOGGER = LoggerFactory.getLogger(ForwardClientService.class); + private static final Logger log = LoggerFactory.getLogger(ForwardClientService.class); private final ChannelManager channelManager; private final ConsumerManager consumerManager; @@ -167,7 +167,7 @@ public class ForwardClientService extends BaseService { this.consumerManager.scanNotActiveChannel(); this.producerManager.scanNotActiveChannel(); } catch (Exception e) { - LOGGER.error("error occurred when scan not active client channels.", e); + log.error("error occurred when scan not active client channels.", e); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java index 554314af56..2316e32c14 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java @@ -61,12 +61,13 @@ public class ConsumerServiceTest extends BaseServiceTest { List messageExtList = Lists.newArrayList( createMessageExt("msg1", "msg1"), - createMessageExt("msg2", "msg2")); + createMessageExt("msg2", "msg2") + ); PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); when(readConsumerClient.popMessage(anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - when(writeConsumerClient.ackMessage(anyString(), any(), anyLong())) + when(writeConsumerClient.ackMessage(anyString(), any())) .thenReturn(CompletableFuture.completedFuture(new AckResult())); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); @@ -98,7 +99,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.ackMessage(anyString(), any(), anyLong())).thenReturn(CompletableFuture.completedFuture(ackResult)); + when(writeConsumerClient.ackMessage(anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); AckMessageResponse response = consumerService.ackMessage(Context.current(), AckMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -121,7 +122,7 @@ public class ConsumerServiceTest extends BaseServiceTest { doAnswer(mock -> { headerRef.set(mock.getArgument(1)); return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBack(anyString(), any(), anyLong()); + }).when(producerClient).sendMessageBack(anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() @@ -150,7 +151,7 @@ public class ConsumerServiceTest extends BaseServiceTest { AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); return CompletableFuture.completedFuture(ackResult); - }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any(), anyLong()); + }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java index 871e91ac9e..2ede5723fd 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java @@ -33,8 +33,6 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -42,9 +40,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; public class ProducerServiceTest extends BaseServiceTest { @@ -69,7 +65,7 @@ public class ProducerServiceTest extends BaseServiceTest { @Test public void testSendMessage() { CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + when(producerClient.sendMessage(anyString(), anyString(), any(), any())) .thenReturn(sendResultFuture); sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), 1L, "txId", "offsetMsgId", "regionId")); @@ -124,7 +120,7 @@ public class ProducerServiceTest extends BaseServiceTest { RuntimeException ex = new RuntimeException(); CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any(), anyLong())) + when(producerClient.sendMessage(anyString(), anyString(), any(), any())) .thenReturn(sendResultFuture); sendResultFuture.completeExceptionally(ex); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java index 45277bf707..83cac79eb7 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java @@ -10,7 +10,6 @@ import apache.rocketmq.v1.QueryOffsetPolicy; import apache.rocketmq.v1.QueryOffsetRequest; import apache.rocketmq.v1.QueryOffsetResponse; import apache.rocketmq.v1.Resource; -import com.google.protobuf.Timestamp; import com.google.protobuf.util.Timestamps; import com.google.rpc.Code; import io.grpc.Context; @@ -23,10 +22,8 @@ import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.assertj.core.util.Lists; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -48,8 +45,8 @@ public class PullMessageServiceTest extends BaseServiceTest { public void testQueryOffset() throws Exception { Context ctx = Context.current(); - when(defaultClient.getMaxOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(CompletableFuture.completedFuture(100L)); - when(defaultClient.searchOffset(anyString(), anyString(), anyInt(), anyLong(), anyLong())).thenReturn(CompletableFuture.completedFuture(50L)); + when(defaultClient.getMaxOffset(anyString(), anyString(), anyInt())).thenReturn(CompletableFuture.completedFuture(100L)); + when(defaultClient.searchOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(CompletableFuture.completedFuture(50L)); QueryOffsetResponse response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() .setPartition(Partition.newBuilder() @@ -108,7 +105,7 @@ public class PullMessageServiceTest extends BaseServiceTest { doAnswer(mock -> { headerRef.set(mock.getArgument(1)); return CompletableFuture.completedFuture(pullResult); - }).when(readConsumerClient).pullMessage(anyString(), any(), anyLong()); + }).when(readConsumerClient).pullMessage(anyString(), any()); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); PullMessageResponse response = pullMessageService.pullMessage(ctx, PullMessageRequest.newBuilder() From e91ccf0bd64e5c57cd7cc1839a0e6cb979c89985 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Mon, 28 Mar 2022 11:48:44 +0800 Subject: [PATCH 074/338] [ISSUE #3949] Do some refactoring work. --- .../proxy/common/utils/ProxyUtils.java | 4 ---- .../connector/AbstractForwardClient.java | 10 +++++---- .../proxy/connector/ConnectorManager.java | 20 ++++++++--------- .../proxy/connector/DefaultForwardClient.java | 16 +++++++++----- .../proxy/connector/ForwardProducer.java | 22 ++++++++++++------- .../proxy/connector/ForwardReadConsumer.java | 11 +++++----- .../proxy/connector/ForwardWriteConsumer.java | 11 +++++----- ...actory.java => AbstractClientManager.java} | 6 ++--- .../factory/AbstractMQClientFactory.java | 2 +- ...Factory.java => ForwardClientManager.java} | 4 ++-- .../connector/route/TopicRouteCache.java | 3 +-- .../TransactionHeartbeatRegisterService.java | 3 +-- .../service/cluster/TransactionService.java | 5 ++--- .../cluster/TransactionServiceTest.java | 3 +-- 14 files changed, 61 insertions(+), 59 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/{AbstractClientFactory.java => AbstractClientManager.java} (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/{ForwardClientFactory.java => ForwardClientManager.java} (96%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index f7c05450b6..6b9ea2cf7e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -16,10 +16,6 @@ */ package org.apache.rocketmq.proxy.common.utils; -import java.time.Duration; - public class ProxyUtils { - public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); - public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 1ea6539a92..c8ca3f563c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -16,25 +16,27 @@ */ package org.apache.rocketmq.proxy.connector; +import java.time.Duration; import java.util.concurrent.ThreadLocalRandom; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; public abstract class AbstractForwardClient implements StartAndShutdown { + public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); - private final ForwardClientFactory clientFactory; + private final ForwardClientManager clientFactory; private MQClientAPIExt[] clients; private final String gidPrefix; - public AbstractForwardClient(ForwardClientFactory clientFactory, String gidPrefix) { + public AbstractForwardClient(ForwardClientManager clientFactory, String gidPrefix) { this.clientFactory = clientFactory; this.gidPrefix = gidPrefix; } protected abstract int getClientNum(); - protected abstract MQClientAPIExt createNewClient(ForwardClientFactory forwardClientFactory, String name); + protected abstract MQClientAPIExt createNewClient(ForwardClientManager forwardClientFactory, String name); protected String getNamePrefix() { return this.gidPrefix; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java index 8ae3c8d7aa..3965208d06 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java @@ -16,14 +16,14 @@ */ package org.apache.rocketmq.proxy.connector; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; public class ConnectorManager extends AbstractStartAndShutdown { - private final ForwardClientFactory forwardClientFactory; + private final ForwardClientManager forwardClientManager; private final DefaultForwardClient defaultForwardClient; private final ForwardProducer forwardProducer; private final ForwardReadConsumer forwardReadConsumer; @@ -33,16 +33,16 @@ public class ConnectorManager extends AbstractStartAndShutdown { private final TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; public ConnectorManager(TransactionStateChecker transactionStateChecker) { - this.forwardClientFactory = new ForwardClientFactory(transactionStateChecker); - this.defaultForwardClient = new DefaultForwardClient(this.forwardClientFactory); - this.forwardProducer = new ForwardProducer(this.forwardClientFactory); - this.forwardReadConsumer = new ForwardReadConsumer(this.forwardClientFactory); - this.forwardWriteConsumer = new ForwardWriteConsumer(this.forwardClientFactory); + this.forwardClientManager = new ForwardClientManager(transactionStateChecker); + this.defaultForwardClient = new DefaultForwardClient(this.forwardClientManager); + this.forwardProducer = new ForwardProducer(this.forwardClientManager); + this.forwardReadConsumer = new ForwardReadConsumer(this.forwardClientManager); + this.forwardWriteConsumer = new ForwardWriteConsumer(this.forwardClientManager); this.topicRouteCache = new TopicRouteCache(this.defaultForwardClient); this.transactionHeartbeatRegisterService = new TransactionHeartbeatRegisterService(this.forwardProducer, this.topicRouteCache); - this.appendStartAndShutdown(this.forwardClientFactory); + this.appendStartAndShutdown(this.forwardClientManager); this.appendStartAndShutdown(this.defaultForwardClient); this.appendStartAndShutdown(this.forwardProducer); this.appendStartAndShutdown(this.forwardReadConsumer); @@ -50,8 +50,8 @@ public class ConnectorManager extends AbstractStartAndShutdown { this.appendStartAndShutdown(this.transactionHeartbeatRegisterService); } - public ForwardClientFactory getForwardClientFactory() { - return forwardClientFactory; + public ForwardClientManager getForwardClientManager() { + return forwardClientManager; } public DefaultForwardClient getDefaultForwardClient() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 711033ae6b..cbe597e88d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -22,15 +22,14 @@ import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; import org.apache.rocketmq.remoting.exception.RemotingException; public class DefaultForwardClient extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; - public DefaultForwardClient(ForwardClientFactory clientFactory) { + public DefaultForwardClient(ForwardClientManager clientFactory) { super(clientFactory, CID_PREFIX); } @@ -40,7 +39,7 @@ public class DefaultForwardClient extends AbstractForwardClient { } @Override - protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getDefaultForwardClientWorkerFactor(); int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); @@ -55,13 +54,18 @@ public class DefaultForwardClient extends AbstractForwardClient { return this.getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); } + public TopicRouteData getTopicRouteInfoFromNameServer(String topic) + throws RemotingException, InterruptedException, MQClientException { + return this.getTopicRouteInfoFromNameServer(topic, DEFAULT_MQ_CLIENT_TIMEOUT); + } + public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) throws RemotingException, InterruptedException, MQClientException { return this.getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId) { - return this.getMaxOffset(brokerAddr, topic, queueId, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.getMaxOffset(brokerAddr, topic, queueId, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture getMaxOffset( @@ -79,7 +83,7 @@ public class DefaultForwardClient extends AbstractForwardClient { int queueId, long timestamp ) { - return this.searchOffset(brokerAddr, topic, queueId, timestamp, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.searchOffset(brokerAddr, topic, queueId, timestamp, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture searchOffset( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 3752fd6f4c..5c362713e9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -26,9 +26,8 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -36,7 +35,7 @@ public class ForwardProducer extends AbstractForwardClient { private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; - public ForwardProducer(ForwardClientFactory clientFactory) { + public ForwardProducer(ForwardClientManager clientFactory) { super(clientFactory, PID_PREFIX); } @@ -46,15 +45,22 @@ public class ForwardProducer extends AbstractForwardClient { } @Override - protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); return clientFactory.getTransactionalProducer(name, threadCount); } - public CompletableFuture heartBeat(String heartbeatAddr, HeartbeatData heartbeatData, long timeout) throws Exception { - return this.getClient().sendHeartbeat(heartbeatAddr, heartbeatData, timeout); + public CompletableFuture heartBeat(String brokerAddr, HeartbeatData heartbeatData) throws Exception { + return this.heartBeat(brokerAddr, heartbeatData, DEFAULT_MQ_CLIENT_TIMEOUT); + } + public CompletableFuture heartBeat(String brokerAddr, HeartbeatData heartbeatData, long timeout) throws Exception { + return this.getClient().sendHeartbeat(brokerAddr, heartbeatData, timeout); + } + + public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader) throws Exception { + this.endTransaction(brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { @@ -67,7 +73,7 @@ public class ForwardProducer extends AbstractForwardClient { Message msg, SendMessageRequestHeader requestHeader ) { - return this.sendMessage(address, brokerName, msg, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.sendMessage(address, brokerName, msg, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture sendMessage( @@ -89,7 +95,7 @@ public class ForwardProducer extends AbstractForwardClient { } public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { - return this.sendMessageBack(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.sendMessageBack(brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 37ee10f95c..1cb9da3a6b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -22,15 +22,14 @@ import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; public class ForwardReadConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_CONSUME_MESSAGE_"; - public ForwardReadConsumer(ForwardClientFactory clientFactory) { + public ForwardReadConsumer(ForwardClientManager clientFactory) { super(clientFactory, CID_PREFIX); } @@ -40,7 +39,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { } @Override - protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); @@ -49,7 +48,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { public CompletableFuture popMessage(String address, String brokerName, PopMessageRequestHeader requestHeader) { - return this.popMessage(address, brokerName, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.popMessage(address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture popMessage( @@ -62,7 +61,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { - return this.pullMessage(address, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.pullMessage(address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 082c8c5963..affd9a868a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -22,16 +22,15 @@ import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientFactory; +import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; import org.apache.rocketmq.remoting.exception.RemotingException; public class ForwardWriteConsumer extends AbstractForwardClient { private static final String CID_PREFIX = "CID_RMQ_PROXY_DELETE_MESSAGE_"; - public ForwardWriteConsumer(ForwardClientFactory clientFactory) { + public ForwardWriteConsumer(ForwardClientManager clientFactory) { super(clientFactory, CID_PREFIX); } @@ -41,7 +40,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { } @Override - protected MQClientAPIExt createNewClient(ForwardClientFactory clientFactory, String name) { + protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); @@ -49,7 +48,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { } public CompletableFuture ackMessage(String address, AckMessageRequestHeader requestHeader) { - return this.ackMessage(address, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.ackMessage(address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture ackMessage( @@ -65,7 +64,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { String brokerName, ChangeInvisibleTimeRequestHeader requestHeader ) { - return this.changeInvisibleTimeAsync(address, brokerName, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return this.changeInvisibleTimeAsync(address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture changeInvisibleTimeAsync( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java index e5ea496c9a..190afd1f8a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java @@ -24,14 +24,14 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public abstract class AbstractClientFactory { - private static final Logger log = LoggerFactory.getLogger(AbstractClientFactory.class); +public abstract class AbstractClientManager { + private static final Logger log = LoggerFactory.getLogger(AbstractClientManager.class); protected final ScheduledExecutorService scheduledExecutorService; protected Map cacheTable = new ConcurrentHashMap<>(); protected RPCHook rpcHook; - public AbstractClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { + public AbstractClientManager(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { this.scheduledExecutorService = scheduledExecutorService; this.rpcHook = rpcHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java index 1a772dc04d..4abcde3316 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java @@ -24,7 +24,7 @@ import org.apache.rocketmq.client.impl.ClientRemotingProcessor; import org.apache.rocketmq.client.impl.MQClientAPIExt; import org.apache.rocketmq.remoting.RPCHook; -public abstract class AbstractMQClientFactory extends AbstractClientFactory { +public abstract class AbstractMQClientFactory extends AbstractClientManager { public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { super(scheduledExecutorService, rpcHook); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index 94cd23f3b3..37ac2f2497 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -28,14 +28,14 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.remoting.RPCHook; -public class ForwardClientFactory implements StartAndShutdown { +public class ForwardClientManager implements StartAndShutdown { private RPCHook rpcHook = null; private final MQClientFactory mqClientFactory; private final TransactionProducerFactory transactionalProducerFactory; - public ForwardClientFactory(TransactionStateChecker transactionStateChecker) { + public ForwardClientManager(TransactionStateChecker transactionStateChecker) { this.init(); ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index b3f62c1a3d..49189a0126 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -29,7 +29,6 @@ import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.AbstractCacheLoader; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; @@ -160,7 +159,7 @@ public class TopicRouteCache { @Override protected TopicRouteData loadTopicRouteData(String topic) throws Exception { - return defaultClient.getTopicRouteInfoFromNameServer(topic, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + return defaultClient.getTopicRouteInfoFromNameServer(topic); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java index 5ae71d5f9b..d7f543b49e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -31,7 +31,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.ForwardProducer; @@ -156,7 +155,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { heartbeatExecutors.submit(() -> { String brokerAddr = brokerData.selectBrokerAddr(); try { - this.forwardProducer.heartBeat(brokerAddr, heartbeatData, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + this.forwardProducer.heartBeat(brokerAddr, heartbeatData); } catch (Exception e) { log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, e); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index bcc4796d8f..c55af42501 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -29,16 +29,15 @@ import java.util.concurrent.ThreadLocalRandom; import org.apache.commons.collections.CollectionUtils; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { @@ -100,7 +99,7 @@ public class TransactionService extends BaseService implements TransactionStateC TransactionId handle = TransactionId.decode(request.getTransactionId()); String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); - this.forwardProducer.endTransaction(brokerAddr, requestHeader, ProxyUtils.DEFAULT_MQ_CLIENT_TIMEOUT); + this.forwardProducer.endTransaction(brokerAddr, requestHeader); future.complete(EndTransactionResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) .build()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java index 86831b75d1..e54529f5e7 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java @@ -20,7 +20,6 @@ import org.mockito.Mock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -77,7 +76,7 @@ public class TransactionServiceTest extends BaseServiceTest { brokerAddrRef.set(mock.getArgument(0)); headerRef.set(mock.getArgument(1)); return null; - }).when(producerClient).endTransaction(anyString(), any(), anyLong()); + }).when(producerClient).endTransaction(anyString(), any()); EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() .setGroup(Resource.newBuilder() From ff3117f322418bf829718ddf657d0d5865a94a66 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Mon, 28 Mar 2022 14:15:49 +0800 Subject: [PATCH 075/338] [ISSUE #3949] Do some refactoring work. --- .../proxy/connector/AbstractForwardClient.java | 3 ++- .../rocketmq/proxy/connector/ForwardProducer.java | 2 +- .../connector/factory/ForwardClientManager.java | 2 +- .../proxy/connector/factory/MQClientFactory.java | 3 +-- .../processor/ProxyClientRemotingProcessor.java | 2 +- .../proxy/connector/route/TopicRouteCache.java | 3 ++- .../TransactionHeartbeatRegisterService.java | 1 - .../connector/transaction/TransactionId.java | 6 +++--- .../proxy/grpc/GrpcMessagingProcessor.java | 15 ++++++++++----- .../apache/rocketmq/proxy/grpc/GrpcServer.java | 5 +++-- .../proxy/grpc/adapter/GrpcConverter.java | 15 +++++---------- .../service/cluster/ForwardClientService.java | 6 ++++-- .../connector/transaction/TransactionIdTest.java | 6 +++--- .../proxy/grpc/service/LocalGrpcServiceTest.java | 2 +- .../service/cluster/TransactionServiceTest.java | 4 ++-- 15 files changed, 39 insertions(+), 36 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index c8ca3f563c..85ad25d855 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -46,7 +46,8 @@ public abstract class AbstractForwardClient implements StartAndShutdown { if (clients.length == 1) { return this.clients[0]; } - return this.clients[ThreadLocalRandom.current().nextInt(this.clients.length)]; + int index = ThreadLocalRandom.current().nextInt(this.clients.length); + return this.clients[index]; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 5c362713e9..f31fe95c32 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -87,7 +87,7 @@ public class ForwardProducer extends AbstractForwardClient { return future.thenApply(sendResult -> { int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { - TransactionId transactionId = TransactionId.genFromBrokerTransactionId(address, sendResult); + TransactionId transactionId = TransactionId.genByBrokerTransactionId(address, sendResult); sendResult.setTransactionId(transactionId.getProxyTransactionId()); } return sendResult; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index 37ac2f2497..0aaa079581 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -30,7 +30,7 @@ import org.apache.rocketmq.remoting.RPCHook; public class ForwardClientManager implements StartAndShutdown { - private RPCHook rpcHook = null; + private RPCHook rpcHook; private final MQClientFactory mqClientFactory; private final TransactionProducerFactory transactionalProducerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java index 07484bd54b..450c611bd7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java @@ -23,8 +23,7 @@ import org.apache.rocketmq.remoting.RPCHook; public class MQClientFactory extends AbstractMQClientFactory { - public MQClientFactory(ScheduledExecutorService scheduledExecutorService, - RPCHook rpcHook) { + public MQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { super(scheduledExecutorService, rpcHook); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java index 3f217294f4..41001e8f6e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java @@ -63,7 +63,7 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { requestHeader.getTranStateTableOffset(), requestHeader.getCommitLogOffset(), requestHeader.getMsgId(), - TransactionId.genFromBrokerTransactionId( + TransactionId.genByBrokerTransactionId( ctx.channel().remoteAddress(), requestHeader.getTransactionId(), requestHeader.getCommitLogOffset(), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index 49189a0126..ad4ed98106 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -81,7 +81,8 @@ public class TopicRouteCache { } public SelectableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { - return getMessageQueue(topic).getWriteSelector().selectOne(brokerName, queueId); + return getMessageQueue(topic).getWriteSelector() + .selectOne(brokerName, queueId); } public SelectableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey) throws Exception { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java index d7f543b49e..a54cb31a39 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -40,7 +40,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TransactionHeartbeatRegisterService implements StartAndShutdown { - private static final Logger log = LoggerFactory.getLogger(TransactionHeartbeatRegisterService.class); private static final String TRANS_HEARTBEAT_CLIENT_ID = "rmq-proxy-producer-client"; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index b909fbecd3..387bb5800d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -54,7 +54,7 @@ public class TransactionId { public TransactionId() { } - public static TransactionId genFromBrokerTransactionId(String brokerAddr, SendResult sendResult) { + public static TransactionId genByBrokerTransactionId(String brokerAddr, SendResult sendResult) { MessageId id = new MessageId(null, 0); try { if (sendResult.getOffsetMsgId() != null) { @@ -65,11 +65,11 @@ public class TransactionId { } catch (Exception e) { log.warn("genFromBrokerTransactionId failed. brokerAddr: {}, sendResult: {}", brokerAddr, sendResult, e); } - return genFromBrokerTransactionId(RemotingUtil.string2SocketAddress(brokerAddr), sendResult.getTransactionId(), + return genByBrokerTransactionId(RemotingUtil.string2SocketAddress(brokerAddr), sendResult.getTransactionId(), id.getOffset(), sendResult.getQueueOffset()); } - public static TransactionId genFromBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, + public static TransactionId genByBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, long commitLogOffset, long tranStateTableOffset) { byte[] orgTransactionIdByte = new byte[0]; if (StringUtils.isNotBlank(orgTransactionId)) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java index f520cc36be..fe8a4f6aac 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java @@ -189,7 +189,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic } @Override - public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { + public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, + StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { @@ -251,7 +252,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic } @Override - public void reportThreadStackTrace(ReportThreadStackTraceRequest request, StreamObserver responseObserver) { + public void reportThreadStackTrace(ReportThreadStackTraceRequest request, + StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.reportThreadStackTrace(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { @@ -264,7 +266,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic } @Override - public void reportMessageConsumptionResult(ReportMessageConsumptionResultRequest request, StreamObserver responseObserver) { + public void reportMessageConsumptionResult(ReportMessageConsumptionResultRequest request, + StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.reportMessageConsumptionResult(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { @@ -277,7 +280,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic } @Override - public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { + public void notifyClientTermination(NotifyClientTerminationRequest request, + StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { @@ -290,7 +294,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic } @Override - public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { + public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, + StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { 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 6ebda585a4..8be76a95d3 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 @@ -97,6 +97,7 @@ public class GrpcServer implements StartAndShutdown { .addService(messagingProcessor) .executor(this.executor); + // grpc interceptors, including acl, logging etc. if (ConfigurationManager.getProxyConfig().isEnableACL()) { List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); if (accessValidators.isEmpty()) { @@ -122,7 +123,7 @@ public class GrpcServer implements StartAndShutdown { this.grpcForwardService.start(); this.server.start(); - log.info("grpc server has started"); + log.info("grpc server start successfully."); } public void shutdown() { @@ -132,7 +133,7 @@ public class GrpcServer implements StartAndShutdown { this.grpcForwardService.shutdown(); - log.info("grpc server has stopped"); + log.info("grpc server shutdown successfully."); } catch (Exception e) { e.printStackTrace(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java index 7199069975..8b5265a049 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java @@ -175,8 +175,7 @@ public class GrpcConverter { public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - String receiptHandleStr = request.getReceiptHandle(); - ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); ackMessageRequestHeader.setConsumerGroup(groupName); @@ -191,8 +190,7 @@ public class GrpcConverter { DelayPolicy delayPolicy) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - String receiptHandleStr = request.getReceiptHandle(); - ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); @@ -209,8 +207,7 @@ public class GrpcConverter { ChangeInvisibleDurationRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - String receiptHandleStr = request.getReceiptHandle(); - ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); @@ -226,8 +223,7 @@ public class GrpcConverter { ForwardMessageToDeadLetterQueueRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - String receiptHandleStr = request.getReceiptHandle(); - ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); @@ -243,8 +239,7 @@ public class GrpcConverter { NackMessageRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - String receiptHandleStr = request.getReceiptHandle(); - ReceiptHandle handle = ReceiptHandle.decode(receiptHandleStr); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index 32e9b76b47..ca6f1e79b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -68,10 +68,12 @@ public class ForwardClientService extends BaseService { this.pollCommandResponseManager = pollCommandResponseManager; this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { - @Override public void handle(ConsumerGroupEvent event, String group, Object... args) { + @Override + public void handle(ConsumerGroupEvent event, String group, Object... args) { } - @Override public void shutdown() { + @Override + public void shutdown() { } }); this.producerManager = new ProducerManager(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java index 4dda6996c8..ab4cfb0201 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java @@ -10,7 +10,7 @@ public class TransactionIdTest { @Test public void test() throws UnknownHostException { - TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "71F99B78B6E261357FA259CCA6456118", 1234, 5678); @@ -24,7 +24,7 @@ public class TransactionIdTest { @Test public void testEmptyTransactionId() throws UnknownHostException { - TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "", 1234, 5678); @@ -38,7 +38,7 @@ public class TransactionIdTest { @Test public void testNullTransactionId() throws UnknownHostException { - TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), null, 1234, 5678); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java index 6a252d2ca8..98b96c123a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java @@ -381,7 +381,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .thenReturn(response); EndTransactionRequest request = EndTransactionRequest.newBuilder() .setMessageId("123") - .setTransactionId(TransactionId.genFromBrokerTransactionId( + .setTransactionId(TransactionId.genByBrokerTransactionId( new InetSocketAddress("0.0.0.0", 80), "123", 123, 123 ).getProxyTransactionId() ) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java index e54529f5e7..73f243b7b0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java @@ -48,7 +48,7 @@ public class TransactionServiceTest extends BaseServiceTest { return null; }).when(channel).writeAndFlush(any()); - TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "71F99B78B6E261357FA259CCA6456118", 1234, 5678); transactionService.checkTransactionState(new TransactionStateCheckRequest( @@ -69,7 +69,7 @@ public class TransactionServiceTest extends BaseServiceTest { public void testEndTransaction() throws Exception { AtomicReference headerRef = new AtomicReference<>(); AtomicReference brokerAddrRef = new AtomicReference<>(); - TransactionId transactionId = TransactionId.genFromBrokerTransactionId( + TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "71F99B78B6E261357FA259CCA6456118", 1234, 5678); doAnswer(mock -> { From 9cf17ebe495739801d1a386b74fd2f4c9156e065 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Mon, 28 Mar 2022 16:45:17 +0800 Subject: [PATCH 076/338] [ISSUE #3949] Do some refactoring work. --- .../rocketmq/client/impl/MQClientAPIExt.java | 29 ++++++++++--------- .../proxy/connector/ForwardProducer.java | 1 - .../connector/transaction/TransactionId.java | 9 ++++-- .../grpc/adapter/channel/ChannelType.java | 2 +- .../adapter/channel/GrpcClientChannel.java | 3 +- .../service/cluster/PullMessageService.java | 1 - 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java index c440cd6c0b..19cbb03970 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java @@ -180,9 +180,10 @@ public class MQClientAPIExt { ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis ) { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + CompletableFuture future = new CompletableFuture<>(); try { - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { RemotingCommand response = responseFuture.getResponseCommand(); if (response != null) { @@ -357,19 +358,19 @@ public class MQClientAPIExt { } public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId, long timeoutMillis) { + GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); + CompletableFuture future = new CompletableFuture<>(); try { - GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { RemotingCommand response = responseFuture.getResponseCommand(); if (response != null) { if (ResponseCode.SUCCESS == response.getCode()) { try { - GetMaxOffsetResponseHeader responseHeader = - (GetMaxOffsetResponseHeader) response.decodeCommandCustomHeader(GetMaxOffsetResponseHeader.class); + GetMaxOffsetResponseHeader responseHeader = response.decodeCommandCustomHeader(GetMaxOffsetResponseHeader.class); future.complete(responseHeader.getOffset()); } catch (Throwable t) { future.completeExceptionally(t); @@ -387,20 +388,20 @@ public class MQClientAPIExt { } public CompletableFuture searchOffset(String brokerAddr, String topic, int queueId , long timestamp, long timeoutMillis) { + SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + requestHeader.setTimestamp(timestamp); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); + CompletableFuture future = new CompletableFuture<>(); try { - SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); - requestHeader.setTimestamp(timestamp); - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); 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); + SearchOffsetResponseHeader responseHeader = response.decodeCommandCustomHeader(SearchOffsetResponseHeader.class); future.complete(responseHeader.getOffset()); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index f31fe95c32..a6f8a0a6e7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -32,7 +32,6 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ForwardProducer extends AbstractForwardClient { - private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; public ForwardProducer(ForwardClientManager clientFactory) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index 387bb5800d..e680c7ad90 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -42,8 +42,13 @@ public class TransactionId { private long tranStateTableOffset; private String proxyTransactionId; - public TransactionId(SocketAddress brokerAddr, String brokerTransactionId, long commitLogOffset, - long tranStateTableOffset, String proxyTransactionId) { + public TransactionId( + SocketAddress brokerAddr, + String brokerTransactionId, + long commitLogOffset, + long tranStateTableOffset, + String proxyTransactionId + ) { this.brokerAddr = brokerAddr; this.brokerTransactionId = brokerTransactionId; this.commitLogOffset = commitLogOffset; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java index 5a883b6a35..da8d30de8d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java @@ -23,7 +23,7 @@ public enum ChannelType { */ LOCAL, /** - * The channel sync from other proxy + * The channel synced from other proxy */ REMOTE } \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index 6a3fcb045d..e389b02713 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -120,8 +120,7 @@ public class GrpcClientChannel extends SimpleChannel { try { switch (command.getCode()) { case RequestCode.CHECK_TRANSACTION_STATE: { - final CheckTransactionStateRequestHeader requestHeader = - (CheckTransactionStateRequestHeader) command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + final CheckTransactionStateRequestHeader requestHeader = command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); future.complete(PollCommandResponse.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index b3fc812089..b5b0545e19 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -41,7 +41,6 @@ import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class PullMessageService extends BaseService { - private final DefaultForwardClient forwardClient; private final ForwardReadConsumer readConsumer; From d6795c4a4b6569e4a8bfe102a028f03ddec11086 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 29 Mar 2022 11:17:29 +0800 Subject: [PATCH 077/338] [ISSUE #3949] add v2 dependency --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d5276af488..22081bdb94 100644 --- a/pom.xml +++ b/pom.xml @@ -454,7 +454,8 @@ ${project.groupId} rocketmq-proto - 5.0.0-SNAPSHOT + 2.0.0-SNAPSHOT + ${project.groupId} From c1d26c8b109b4fcde43e68701dde3f587b697f45 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 30 Mar 2022 14:59:29 +0800 Subject: [PATCH 078/338] [ISSUE #3949] Import compatible rocketmq-proto. --- acl/pom.xml | 2 ++ pom.xml | 1 - proxy/pom.xml | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/acl/pom.xml b/acl/pom.xml index c80cc24b5c..ce9c9d6411 100644 --- a/acl/pom.xml +++ b/acl/pom.xml @@ -22,6 +22,8 @@ ${project.groupId} rocketmq-proto + 2.0.0-SNAPSHOT + compatible ${project.groupId} diff --git a/pom.xml b/pom.xml index 22081bdb94..9e0faf55e7 100644 --- a/pom.xml +++ b/pom.xml @@ -455,7 +455,6 @@ ${project.groupId} rocketmq-proto 2.0.0-SNAPSHOT - ${project.groupId} diff --git a/proxy/pom.xml b/proxy/pom.xml index 944de82261..ead6de6a5b 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -39,6 +39,8 @@ org.apache.rocketmq rocketmq-proto + 2.0.0-SNAPSHOT + compatible org.apache.rocketmq From 7257add69bdd474444416e527b16a086ebc7adc7 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 30 Mar 2022 14:24:37 +0800 Subject: [PATCH 079/338] [ISSUE #3949] test cases --- .../java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java | 2 ++ .../apache/rocketmq/proxy/connector/ForwardReadConsumer.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index 6b9ea2cf7e..4cca5a3aec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -18,4 +18,6 @@ package org.apache.rocketmq.proxy.common.utils; public class ProxyUtils { public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; + + public static final long MAX_CONSUMER_TIMEOUT_MILLIS = Duration.ofSeconds(20).toMillis(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 1cb9da3a6b..f9bf870321 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -61,7 +61,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { - return this.pullMessage(address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.pullMessage(address, requestHeader, ProxyUtils.MAX_CONSUMER_TIMEOUT_MILLIS); } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, From 0bdd9224f6545ba594acf590eb0392691b1da298 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 30 Mar 2022 16:48:52 +0800 Subject: [PATCH 080/338] [ISSUE #3949] code refactor --- .../java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java | 2 -- .../apache/rocketmq/proxy/connector/AbstractForwardClient.java | 1 + .../apache/rocketmq/proxy/connector/ForwardReadConsumer.java | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index 4cca5a3aec..6b9ea2cf7e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -18,6 +18,4 @@ package org.apache.rocketmq.proxy.common.utils; public class ProxyUtils { public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; - - public static final long MAX_CONSUMER_TIMEOUT_MILLIS = Duration.ofSeconds(20).toMillis(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 85ad25d855..12a3354f48 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -23,6 +23,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; public abstract class AbstractForwardClient implements StartAndShutdown { + public static final long MAX_CONSUMER_TIMEOUT_MILLIS = Duration.ofSeconds(20).toMillis(); public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); private final ForwardClientManager clientFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index f9bf870321..3bb0a852eb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -61,7 +61,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { - return this.pullMessage(address, requestHeader, ProxyUtils.MAX_CONSUMER_TIMEOUT_MILLIS); + return this.pullMessage(address, requestHeader, MAX_CONSUMER_TIMEOUT_MILLIS); } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, From d051fe9d7d132612eca34cdc3b82ba1623296b25 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 30 Mar 2022 16:44:06 +0800 Subject: [PATCH 081/338] [ISSUE #3949] code refactor --- .../connector/AbstractForwardClient.java | 2 +- .../proxy/connector/DefaultForwardClient.java | 8 +-- .../proxy/connector/ForwardProducer.java | 8 +-- .../proxy/connector/ForwardReadConsumer.java | 6 +- .../proxy/connector/ForwardWriteConsumer.java | 4 +- .../connector/client}/MQClientAPIExt.java | 69 ++++++------------- .../factory/AbstractMQClientFactory.java | 2 +- .../factory/ForwardClientManager.java | 2 +- 8 files changed, 37 insertions(+), 64 deletions(-) rename {client/src/main/java/org/apache/rocketmq/client/impl => proxy/src/main/java/org/apache/rocketmq/proxy/connector/client}/MQClientAPIExt.java (86%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java index 12a3354f48..2dce57491e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java @@ -18,7 +18,7 @@ package org.apache.rocketmq.proxy.connector; import java.time.Duration; import java.util.concurrent.ThreadLocalRandom; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index cbe597e88d..3cf8bd9334 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -51,7 +51,7 @@ public class DefaultForwardClient extends AbstractForwardClient { GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis ) { - return this.getClient().getConsumerListByGroup(brokerAddr, requestHeader, timeoutMillis); + return this.getClient().getConsumerListByGroupAsync(brokerAddr, requestHeader, timeoutMillis); } public TopicRouteData getTopicRouteInfoFromNameServer(String topic) @@ -74,7 +74,7 @@ public class DefaultForwardClient extends AbstractForwardClient { int queueId, long timeoutMillis ) { - return this.getClient().getMaxOffset(brokerAddr, topic, queueId, timeoutMillis); + return this.getClient().getMaxOffsetAsync(brokerAddr, topic, queueId, timeoutMillis); } public CompletableFuture searchOffset( @@ -93,6 +93,6 @@ public class DefaultForwardClient extends AbstractForwardClient { long timestamp, long timeoutMillis ) { - return this.getClient().searchOffset(brokerAddr, topic, queueId, timestamp, timeoutMillis); + return this.getClient().searchOffsetAsync(brokerAddr, topic, queueId, timestamp, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index a6f8a0a6e7..f3b40078c9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.Message; @@ -55,7 +55,7 @@ public class ForwardProducer extends AbstractForwardClient { return this.heartBeat(brokerAddr, heartbeatData, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture heartBeat(String brokerAddr, HeartbeatData heartbeatData, long timeout) throws Exception { - return this.getClient().sendHeartbeat(brokerAddr, heartbeatData, timeout); + return this.getClient().sendHeartbeatAsync(brokerAddr, heartbeatData, timeout); } public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader) throws Exception { @@ -82,7 +82,7 @@ public class ForwardProducer extends AbstractForwardClient { SendMessageRequestHeader requestHeader, long timeoutMillis ) { - CompletableFuture future = this.getClient().sendMessage(address, brokerName, msg, requestHeader, timeoutMillis); + CompletableFuture future = this.getClient().sendMessageAsync(address, brokerName, msg, requestHeader, timeoutMillis); return future.thenApply(sendResult -> { int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { @@ -98,6 +98,6 @@ public class ForwardProducer extends AbstractForwardClient { } public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { - return this.getClient().sendMessageBack(brokerAddr, requestHeader, timeoutMillis); + return this.getClient().sendMessageBackAsync(brokerAddr, requestHeader, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index 3bb0a852eb..e45db1cbf3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -19,7 +19,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -57,7 +57,7 @@ public class ForwardReadConsumer extends AbstractForwardClient { PopMessageRequestHeader requestHeader, long timeoutMillis ) { - return this.getClient().popMessage(address, brokerName, requestHeader, timeoutMillis); + return this.getClient().popMessageAsync(address, brokerName, requestHeader, timeoutMillis); } public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { @@ -66,6 +66,6 @@ public class ForwardReadConsumer extends AbstractForwardClient { public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, long timeoutMillis) { - return this.getClient().pullMessage(address, requestHeader, timeoutMillis); + return this.getClient().pullMessageAsync(address, requestHeader, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index affd9a868a..60332c063b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -18,7 +18,7 @@ package org.apache.rocketmq.proxy.connector; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; @@ -56,7 +56,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { AckMessageRequestHeader requestHeader, long timeoutMillis ) { - return this.getClient().ackMessage(address, requestHeader, timeoutMillis); + return this.getClient().ackMessageAsync(address, requestHeader, timeoutMillis); } public CompletableFuture changeInvisibleTimeAsync( diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java similarity index 86% rename from client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java index 19cbb03970..5a59d9991e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.client.impl; +package org.apache.rocketmq.proxy.connector.client; import java.util.Collections; import java.util.List; @@ -28,6 +28,9 @@ import org.apache.rocketmq.client.consumer.PullCallback; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.client.impl.CommunicationMode; +import org.apache.rocketmq.client.impl.MQClientAPIImpl; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.RequestCode; @@ -35,7 +38,6 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; @@ -47,9 +49,7 @@ import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.remoting.RemotingClient; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; @@ -57,11 +57,10 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MQClientAPIExt { +public class MQClientAPIExt extends MQClientAPIImpl { private static final Logger LOGGER = LoggerFactory.getLogger(MQClientAPIExt.class); private final ClientConfig clientConfig; - private final MQClientAPIImpl mqClientAPI; public MQClientAPIExt( ClientConfig clientConfig, @@ -69,25 +68,13 @@ public class MQClientAPIExt { ClientRemotingProcessor clientRemotingProcessor, RPCHook rpcHook ) { + super(nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig); this.clientConfig = clientConfig; - this.mqClientAPI = new MQClientAPIImpl(nettyClientConfig, clientRemotingProcessor, rpcHook, clientConfig); - } - - public void start() { - this.mqClientAPI.start(); - } - - public void shutdown() { - this.mqClientAPI.shutdown(); - } - - public void fetchNameServerAddr() { - this.mqClientAPI.fetchNameServerAddr(); } public boolean updateNameServerAddressList() { if (this.clientConfig.getNamesrvAddr() != null) { - this.mqClientAPI.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); + this.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); LOGGER.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); return true; } @@ -107,11 +94,7 @@ public class MQClientAPIExt { return ex; } - protected RemotingClient getRemotingClient() { - return this.mqClientAPI.getRemotingClient(); - } - - public CompletableFuture sendHeartbeat( + public CompletableFuture sendHeartbeatAsync( String brokerAddr, HeartbeatData heartbeatData, long timeoutMillis @@ -140,12 +123,7 @@ public class MQClientAPIExt { return future; } - public void endTransactionOneway(String brokerAddr, EndTransactionRequestHeader requestHeader, String remark, long timeoutMillis) - throws MQBrokerException, RemotingException, InterruptedException { - this.mqClientAPI.endTransactionOneway(brokerAddr, requestHeader, remark, timeoutMillis); - } - - public CompletableFuture sendMessage( + public CompletableFuture sendMessageAsync( String brokerAddr, String brokerName, Message msg, @@ -161,7 +139,7 @@ public class MQClientAPIExt { RemotingCommand response = responseFuture.getResponseCommand(); if (response != null) { try { - future.complete(mqClientAPI.processSendResponse(brokerName, msg, response, brokerAddr)); + future.complete(this.processSendResponse(brokerName, msg, response, brokerAddr)); } catch (Exception e) { future.completeExceptionally(e); } @@ -175,7 +153,7 @@ public class MQClientAPIExt { return future; } - public CompletableFuture sendMessageBack( + public CompletableFuture sendMessageBackAsync( String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis @@ -198,7 +176,7 @@ public class MQClientAPIExt { return future; } - public CompletableFuture popMessage( + public CompletableFuture popMessageAsync( String brokerAddr, String brokerName, PopMessageRequestHeader requestHeader, @@ -206,7 +184,7 @@ public class MQClientAPIExt { ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.popMessageAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new PopCallback() { + this.popMessageAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new PopCallback() { @Override public void onSuccess(PopResult popResult) { future.complete(popResult); @@ -223,14 +201,14 @@ public class MQClientAPIExt { return future; } - public CompletableFuture ackMessage( + public CompletableFuture ackMessageAsync( String brokerAddr, AckMessageRequestHeader requestHeader, long timeoutMillis ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.ackMessageAsync(brokerAddr, timeoutMillis, new AckCallback() { + this.ackMessageAsync(brokerAddr, timeoutMillis, new AckCallback() { @Override public void onSuccess(AckResult ackResult) { future.complete(ackResult); @@ -255,7 +233,7 @@ public class MQClientAPIExt { ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, + this.changeInvisibleTimeAsync(brokerName, brokerAddr, requestHeader, timeoutMillis, new AckCallback() { @Override public void onSuccess(AckResult ackResult) { @@ -274,14 +252,14 @@ public class MQClientAPIExt { return future; } - public CompletableFuture pullMessage( + public CompletableFuture pullMessageAsync( String brokerAddr, PullMessageRequestHeader requestHeader, long timeoutMillis ) { CompletableFuture future = new CompletableFuture<>(); try { - this.mqClientAPI.pullMessage(brokerAddr, requestHeader, timeoutMillis, CommunicationMode.ASYNC, + this.pullMessage(brokerAddr, requestHeader, timeoutMillis, CommunicationMode.ASYNC, new PullCallback() { @Override public void onSuccess(PullResult pullResult) { @@ -309,7 +287,7 @@ public class MQClientAPIExt { this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); } - public CompletableFuture> getConsumerListByGroup( + public CompletableFuture> getConsumerListByGroupAsync( String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis @@ -352,12 +330,7 @@ public class MQClientAPIExt { return future; } - public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) - throws RemotingException, InterruptedException, MQClientException { - return this.mqClientAPI.getTopicRouteInfoFromNameServer(topic, timeoutMillis); - } - - public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId, long timeoutMillis) { + public CompletableFuture getMaxOffsetAsync(String brokerAddr, String topic, int queueId, long timeoutMillis) { GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); requestHeader.setTopic(topic); requestHeader.setQueueId(queueId); @@ -387,7 +360,7 @@ public class MQClientAPIExt { return future; } - public CompletableFuture searchOffset(String brokerAddr, String topic, int queueId , long timestamp, long timeoutMillis) { + public CompletableFuture searchOffsetAsync(String brokerAddr, String topic, int queueId , long timestamp, long timeoutMillis) { SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); requestHeader.setTopic(topic); requestHeader.setQueueId(queueId); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java index 4abcde3316..37a0cedabc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java @@ -21,7 +21,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.impl.ClientRemotingProcessor; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.remoting.RPCHook; public abstract class AbstractMQClientFactory extends AbstractClientManager { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index 0aaa079581..fb8c12505c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -21,7 +21,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.client.impl.MQClientAPIExt; +import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.StartAndShutdown; From 041bce0d4a1cd4f288962038632a21a008755761 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Thu, 31 Mar 2022 10:10:06 +0800 Subject: [PATCH 082/338] [ISSUE #3949] Do refactor some code for readability. --- .../rocketmq/proxy/channel/ChannelManager.java | 10 ++++------ .../rocketmq/proxy/grpc/adapter/GrpcConverter.java | 6 +++--- .../proxy/grpc/adapter/InvocationContext.java | 4 ++-- .../rocketmq/proxy/grpc/adapter/ResponseWriter.java | 13 ++----------- .../grpc/adapter/channel/GrpcClientChannel.java | 5 ++--- .../proxy/grpc/service/LocalGrpcService.java | 4 ++-- .../grpc/service/cluster/ForwardClientService.java | 4 ++-- 7 files changed, 17 insertions(+), 29 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 3b751aec64..6c6349bdd1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.channel; -import com.google.common.base.Strings; import io.grpc.Context; import java.util.ArrayList; import java.util.Collections; @@ -28,9 +27,10 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.common.Cleaner; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.slf4j.Logger; @@ -54,14 +54,12 @@ public class ChannelManager { } public T createChannel(String clientId, Supplier creator, Class clazz) { - if (Strings.isNullOrEmpty(clientId)) { + if (StringUtils.isBlank(clientId)) { log.warn("ClientId is unexpected null or empty"); return creator.get(); } - if (!clientIdChannelMap.containsKey(clientId)) { - clientIdChannelMap.putIfAbsent(clientId, creator.get()); - } + clientIdChannelMap.computeIfAbsent(clientId, key -> creator.get()); T channel = clazz.cast(clientIdChannelMap.get(clientId)); channel.updateLastAccessTime(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java index 8b5265a049..46c8d3d6ae 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java @@ -678,10 +678,10 @@ public class GrpcConverter { return consumeMessageDirectlyResult; } - public static Resource buildResource(String resourceNameWithNamespace) { + public static Resource buildResource(String resourceStr) { return Resource.newBuilder() - .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) - .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceStr)) + .setName(NamespaceUtil.withoutNamespace(resourceStr)) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java index bdf2ef601f..1260b0b04b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.grpc.adapter; +import java.time.Duration; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; public class InvocationContext { private final R request; @@ -31,7 +31,7 @@ public class InvocationContext { } public boolean expired(long expiredTimeSec) { - return System.currentTimeMillis() - timestamp >= TimeUnit.SECONDS.toMillis(expiredTimeSec); + return System.currentTimeMillis() - timestamp >= Duration.ofSeconds(expiredTimeSec).toMillis(); } public R getRequest() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java index 44860e1919..88d123758e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java @@ -44,27 +44,18 @@ public class ResponseWriter { } } - public static void writeException(StreamObserver observer, final Throwable e) { + public static void writeException(StreamObserver observer, final Throwable e) { if (observer instanceof ServerCallStreamObserver) { - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (null == e) { return; } + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (serverCallStreamObserver.isCancelled()) { log.warn("Client has cancelled the request. Exception to write", e); return; } -// if (e instanceof CompletionException) { -// if (e.getCause() instanceof ProxyException) { -// ProxyException proxyException = (ProxyException) e.getCause(); -// serverCallStreamObserver.onNext(ResponseBuilder.buildCommon(proxyException.getCode(), proxyException.getMessage())); -// serverCallStreamObserver.onCompleted(); -// return; -// } -// } - log.debug("Start to write error response", e); serverCallStreamObserver.onError(e); serverCallStreamObserver.onCompleted(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java index e389b02713..bcdc46173f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java @@ -53,7 +53,7 @@ public class GrpcClientChannel extends SimpleChannel { this.manager = manager; } - public void addClientObserver(CompletableFuture future) { + public void setClientObserver(CompletableFuture future) { this.pollCommandResponseFutureRef.set(future); } @@ -131,8 +131,7 @@ public class GrpcClientChannel extends SimpleChannel { break; } case RequestCode.GET_CONSUMER_RUNNING_INFO: { - final GetConsumerRunningInfoRequestHeader requestHeader = - (GetConsumerRunningInfoRequestHeader) command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); + final GetConsumerRunningInfoRequestHeader requestHeader = command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); if (!requestHeader.isJstackEnable()) { break; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index 88b1853022..b562c15132 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -420,7 +420,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .build()); break; } - producerChannel.addClientObserver(future); + producerChannel.setClientObserver(future); break; case CONSUMER_GROUP: Resource consumerGroup = request.getConsumerGroup(); @@ -432,7 +432,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .build()); break; } - consumerChannel.addClientObserver(future); + consumerChannel.setClientObserver(future); break; default: break; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java index ca6f1e79b4..52f79f6e8c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java @@ -145,7 +145,7 @@ public class ForwardClientService extends BaseService { if (producerChannel == null) { future.complete(noopCommandResponse); } else { - producerChannel.addClientObserver(future); + producerChannel.setClientObserver(future); } break; case CONSUMER_GROUP: @@ -155,7 +155,7 @@ public class ForwardClientService extends BaseService { if (consumerChannel == null) { future.complete(noopCommandResponse); } else { - consumerChannel.addClientObserver(future); + consumerChannel.setClientObserver(future); } break; default: From e4110ae7f7592e6625290015342e67606f963c99 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 1 Apr 2022 16:25:52 +0800 Subject: [PATCH 083/338] [ISSUE #3949] v2 support --- .../proxy/connector/ForwardProducer.java | 19 +- .../connector/client/MQClientAPIExt.java | 36 ++ .../TransactionHeartbeatRegisterService.java | 52 +- .../proxy/grpc/GrpcMessagingProcessorV2.java | 254 ++++++++ .../proxy/grpc/adapter/GrpcConverterV2.java | 597 ++++++++++++++++++ .../proxy/grpc/adapter/ProxyExceptionV2.java | 38 ++ .../proxy/grpc/adapter/ResponseBuilderV2.java | 112 ++++ .../interceptor/InterceptorConstants.java | 3 + .../grpc/service/ClusterGrpcService.java | 8 +- .../grpc/service/ClusterGrpcServiceV2.java | 181 ++++++ .../proxy/grpc/service/GrpcClientManager.java | 54 ++ .../grpc/service/GrpcForwardServiceV2.java | 76 +++ .../cluster/AssignmentQueueSelector.java | 2 +- .../grpc/service/cluster/BaseService.java | 20 +- .../grpc/service/cluster/ConsumerService.java | 79 ++- .../DefaultAssignmentQueueSelector.java | 6 +- .../cluster/DefaultReadQueueSelector.java | 6 +- .../cluster/DefaultWriteQueueSelector.java | 15 +- .../grpc/service/cluster/ProducerService.java | 57 +- .../service/cluster/PullMessageService.java | 38 +- .../service/cluster/ReadQueueSelector.java | 2 +- .../grpc/service/cluster/RouteService.java | 78 +-- .../service/cluster/TransactionService.java | 30 +- .../service/cluster/WriteQueueSelector.java | 6 +- .../service/cluster/RouteServiceTest.java | 64 +- 25 files changed, 1617 insertions(+), 216 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index f3b40078c9..442efc9329 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.client.producer.SendResult; @@ -69,7 +70,7 @@ public class ForwardProducer extends AbstractForwardClient { public CompletableFuture sendMessage( String address, String brokerName, - Message msg, + List msg, SendMessageRequestHeader requestHeader ) { return this.sendMessage(address, brokerName, msg, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); @@ -78,11 +79,23 @@ public class ForwardProducer extends AbstractForwardClient { public CompletableFuture sendMessage( String address, String brokerName, - Message msg, + List msg, SendMessageRequestHeader requestHeader, long timeoutMillis ) { - CompletableFuture future = this.getClient().sendMessageAsync(address, brokerName, msg, requestHeader, timeoutMillis); + CompletableFuture future; + if (msg.size() == 1) { + future = this.getClient().sendMessageAsync(address, brokerName, msg.get(0), requestHeader, timeoutMillis); + } else { + future = this.getClient().sendMessageAsync(address, brokerName, msg, requestHeader, timeoutMillis); + } + return processSendMessageResponseFuture(address, requestHeader, future); + } + + private CompletableFuture processSendMessageResponseFuture( + String address, + SendMessageRequestHeader requestHeader, + CompletableFuture future) { return future.thenApply(sendResult -> { int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java index 5a59d9991e..4859587348 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java @@ -33,6 +33,8 @@ import org.apache.rocketmq.client.impl.CommunicationMode; import org.apache.rocketmq.client.impl.MQClientAPIImpl; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; @@ -153,6 +155,40 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } + public CompletableFuture sendMessageAsync( + String brokerAddr, + String brokerName, + List msgList, + SendMessageRequestHeader requestHeader, + long timeoutMillis + ) { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_BATCH_MESSAGE, requestHeader); + + CompletableFuture future = new CompletableFuture<>(); + try { + requestHeader.setBatch(true); + MessageBatch msgBatch = MessageBatch.generateFromList(msgList); + MessageClientIDSetter.setUniqID(msgBatch); + msgBatch.setBody(msgBatch.encode()); + + 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)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + public CompletableFuture sendMessageBackAsync( String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java index a54cb31a39..d754910f5d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -18,7 +18,9 @@ package org.apache.rocketmq.proxy.connector.transaction; import com.google.common.collect.Sets; 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; @@ -56,25 +58,51 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { this.topicRouteCache = topicRouteCache; } + public void addProducerGroup(String group, List topicList) { + for (String topic : topicList) { + addProducerGroup(group, topic); + } + } + public void addProducerGroup(String group, String topic) { + try { + groupClusterData.compute(group, (groupName, clusterDataSet) -> { + if (clusterDataSet == null) { + clusterDataSet = Sets.newHashSet(); + } + clusterDataSet.addAll(getClusterDataFromTopic(topic)); + return clusterDataSet; + }); + } catch (Exception e) { + log.error("add producer group err in txHeartBeat. groupId: {}, err: {}", group, e); + } + } + + public void replaceProducerGroup(String group, List topicList) { + Set clusterDataSet = new HashSet<>(); + for (String topic : topicList) { + clusterDataSet.addAll(getClusterDataFromTopic(topic)); + } + groupClusterData.put(group, clusterDataSet); + } + + private Set getClusterDataFromTopic(String topic) { try { MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(topic); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); - if (brokerDataList != null) { - for (BrokerData brokerData : brokerDataList) { - groupClusterData.compute(group, (groupName, clusterDataSet) -> { - if (clusterDataSet == null) { - clusterDataSet = Sets.newHashSet(); - } - clusterDataSet.add(new ClusterData(brokerData.getCluster())); - return clusterDataSet; - }); - } + if (brokerDataList == null) { + return Collections.emptySet(); } - } catch (Exception e) { - log.error("add producer group err in txHeartBeat. groupId: {}, err: {}", group, e); + Set res = Sets.newHashSet(); + for (BrokerData brokerData : brokerDataList) { + res.add(new ClusterData(brokerData.getCluster())); + } + return res; + } catch (Throwable t) { + log.error("get cluster data failed in txHeartBeat. topic: {}, err: {}", topic, t); } + return Collections.emptySet(); } public void onProducerGroupOffline(String group) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java new file mode 100644 index 0000000000..9315381445 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java @@ -0,0 +1,254 @@ +/* + * 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.grpc; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.Status; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.service.GrpcForwardServiceV2; + +public class GrpcMessagingProcessorV2 extends MessagingServiceGrpc.MessagingServiceImplBase { + + private final GrpcForwardServiceV2 grpcForwardService; + + public GrpcMessagingProcessorV2(GrpcForwardServiceV2 grpcForwardService) { + this.grpcForwardService = grpcForwardService; + } + + public Status convertExceptionToStatus(Throwable t) { + if (t instanceof CompletionException) { + if (t.getCause() instanceof ProxyExceptionV2) { + ProxyExceptionV2 proxyException = (ProxyExceptionV2) t.getCause(); + return ResponseBuilderV2.buildStatus(proxyException.getCode(), proxyException.getMessage()); + } + } + return ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); + } + + @Override + public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryRoute(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + QueryRouteResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.heartbeat(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + HeartbeatResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + SendMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void queryAssignment(QueryAssignmentRequest request, + StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryAssignment(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + QueryAssignmentResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.receiveMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ReceiveMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + AckMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, + StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.endTransaction(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + EndTransactionResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void queryOffset(QueryOffsetRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.queryOffset(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + QueryOffsetResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void pullMessage(PullMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.pullMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + PullMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void notifyClientTermination(NotifyClientTerminationRequest request, + StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + NotifyClientTerminationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, + StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ChangeInvisibleDurationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + + @Override + public StreamObserver telemetry(StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(TelemetryCommand request) { + + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onCompleted() { + + } + }; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java new file mode 100644 index 0000000000..41a8e35b80 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java @@ -0,0 +1,597 @@ +/* + * 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.grpc.adapter; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Digest; +import apache.rocketmq.v2.DigestType; +import apache.rocketmq.v2.Encoding; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.MessageType; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SubscriptionEntry; +import apache.rocketmq.v2.SystemProperties; +import apache.rocketmq.v2.TransactionResolution; +import apache.rocketmq.v2.TransactionSource; +import apache.rocketmq.v2.VerifyMessageResult; +import com.google.common.collect.Maps; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import io.grpc.Context; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.constant.ConsumeInitMode; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.filter.ExpressionType; +import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.common.sysflag.PullSysFlag; +import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GrpcConverterV2 { + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + public static String wrapResourceWithNamespace(Resource resource) { + return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); + } + + public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, String producerGroup) { + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + + MessageQueue messageQueue = request.getMessageQueue(); + + if (request.getMessagesCount() <= 0) { + throw new ProxyExceptionV2(Code.MESSAGE_CORRUPTED, "no message to send"); + } + Message message = request.getMessages(0); + SystemProperties systemProperties = message.getSystemProperties(); + + Map property = buildMessageProperty(message, producerGroup); + requestHeader.setProducerGroup(producerGroup); + requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); + requestHeader.setDefaultTopic(""); + requestHeader.setDefaultTopicQueueNums(0); + requestHeader.setQueueId(messageQueue.getId()); + // sysFlag (body encoding & message type) + int sysFlag = 0; + Encoding bodyEncoding = systemProperties.getBodyEncoding(); + if (bodyEncoding.equals(Encoding.GZIP)) { + sysFlag |= MessageSysFlag.COMPRESSED_FLAG; + } + // transaction + MessageType messageType = systemProperties.getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; + } + requestHeader.setSysFlag(sysFlag); + requestHeader.setBornTimestamp(Timestamps.toMillis(systemProperties.getBornTimestamp())); + requestHeader.setFlag(0); + requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); + requestHeader.setReconsumeTimes(systemProperties.getDeliveryAttempt()); + + return requestHeader; + } + + public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { + Resource group = request.getGroup(); + String groupName = GrpcConverterV2.wrapResourceWithNamespace(group); + MessageQueue messageQueue = request.getMessageQueue(); + Resource topic = messageQueue.getTopic(); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); + int queueId = messageQueue.getId(); + int maxMessageNumbers = request.getBatchSize(); + if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { + log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", + maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); + maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; + } + long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); + long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); + + FilterExpression filterExpression = request.getFilterExpression(); + String expression = filterExpression.getExpression(); + String expressionType = GrpcConverterV2.buildExpressionType(filterExpression.getType()); + + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setConsumerGroup(groupName); + requestHeader.setTopic(topicName); + requestHeader.setQueueId(queueId); + requestHeader.setMaxMsgNums(maxMessageNumbers); + requestHeader.setInvisibleTime(invisibleTime); + requestHeader.setPollTime(pollTime); + requestHeader.setBornTime(bornTime); + requestHeader.setInitMode(ConsumeInitMode.MAX); + requestHeader.setExpType(expressionType); + requestHeader.setExp(expression); + requestHeader.setOrder(request.getFifo()); + + return requestHeader; + } + + public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + ackMessageRequestHeader.setConsumerGroup(groupName); + ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + return ackMessageRequestHeader; + } + + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader( + ChangeInvisibleDurationRequest request) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); + return changeInvisibleTimeRequestHeader; + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( + ForwardMessageToDeadLetterQueueRequest request) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); + return consumerSendMsgBackRequestHeader; + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( + ChangeInvisibleDurationRequest request, String messageId, int maxReconsumeTimes) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); + return consumerSendMsgBackRequestHeader; + } + + public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, String producerGroup) { + String messageId = request.getMessageId(); + String transactionId = request.getTransactionId(); + TransactionId handle; + try { + handle = TransactionId.decode(transactionId); + } catch (Exception e) { + throw new ProxyExceptionV2(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); + } + long transactionStateTableOffset = handle.getTranStateTableOffset(); + long commitLogOffset = handle.getCommitLogOffset(); + boolean fromTransactionCheck = request.getSource() == TransactionSource.SOURCE_SERVER_CHECK; + int commitOrRollback = GrpcConverterV2.buildTransactionCommitOrRollback(request.getResolution()); + + EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); + endTransactionRequestHeader.setProducerGroup(producerGroup); + endTransactionRequestHeader.setMsgId(messageId); + endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); + endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); + endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); + endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); + endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); + + return endTransactionRequestHeader; + } + + public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { + MessageQueue messageQueue = request.getMessageQueue(); + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(messageQueue.getTopic()); + + int queueId = messageQueue.getId(); + int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); + String expression = request.getFilterExpression().getExpression(); + String expressionType = GrpcConverterV2.buildExpressionType(request.getFilterExpression().getType()); + + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup(groupName); + requestHeader.setTopic(topicName); + requestHeader.setQueueId(queueId); + requestHeader.setQueueOffset(request.getOffset()); + requestHeader.setMaxMsgNums(request.getBatchSize()); + requestHeader.setSysFlag(sysFlag); + requestHeader.setCommitOffset(0L); + requestHeader.setSuspendTimeoutMillis(pollTimeoutInMillis); + requestHeader.setSubscription(expression); + requestHeader.setSubVersion(0L); + requestHeader.setExpressionType(expressionType); + return requestHeader; + } + + public static Map buildMessageProperty(Message message, String producerGroup) { + org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); + // set user properties + Map userProperties = message.getUserPropertiesMap(); + for (String key : userProperties.keySet()) { + if (MessageConst.STRING_HASH_SET.contains(key)) { + throw new ProxyExceptionV2(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); + } + } + MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); + + // set tag + String tag = message.getSystemProperties().getTag(); + if (!"".equals(tag)) { + messageWithHeader.setTags(tag); + } + + // set keys + List keysList = message.getSystemProperties().getKeysList(); + if (keysList.size() > 0) { + messageWithHeader.setKeys(keysList); + } + + // set message id + String messageId = message.getSystemProperties().getMessageId(); + if ("".equals(messageId)) { + throw new ProxyExceptionV2(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); + } + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); + + // set transaction property + MessageType messageType = message.getSystemProperties().getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); + + Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); + + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, + String.valueOf(Durations.toSeconds(transactionResolveDelay))); + } + + // set delay level or deliver timestamp + if (message.getSystemProperties().hasDeliveryTimestamp()) { + Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); + String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); + } + + // set reconsume times + int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); + MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); + // set producer group + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); + // set message group + String messageGroup = message.getSystemProperties().getMessageGroup(); + if (!messageGroup.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); + } + // set trace context + String traceContext = message.getSystemProperties().getTraceContext(); + if (!traceContext.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); + } + return messageWithHeader.getProperties(); + } + + public static List buildMessage(List protoMessageList, String producerGroup) { + List messages = new ArrayList<>(); + for (Message protoMessage : protoMessageList) { + messages.add(buildMessage(protoMessage, producerGroup)); + } + return messages; + } + + public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage, String producerGroup) { + String topic = wrapResourceWithNamespace(protoMessage.getTopic()); + + org.apache.rocketmq.common.message.Message message = + new org.apache.rocketmq.common.message.Message(topic, protoMessage.getBody().toByteArray()); + Map messageProperty = buildMessageProperty(protoMessage, producerGroup); + + MessageAccessor.setProperties(message, messageProperty); + return message; + } + + public static String buildExpressionType(FilterType filterType) { + switch (filterType) { + case SQL: + return ExpressionType.SQL92; + case TAG: + default: + return ExpressionType.TAG; + } + } + + public static Set buildSubscriptionDataSet(List subscriptionEntryList) { + Set subscriptionDataSet = new HashSet<>(); + for (SubscriptionEntry sub : subscriptionEntryList) { + String topicName = GrpcConverterV2.wrapResourceWithNamespace(sub.getTopic()); + FilterExpression filterExpression = sub.getExpression(); + subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); + } + return subscriptionDataSet; + } + + public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { + String expression = filterExpression.getExpression(); + String expressionType = GrpcConverterV2.buildExpressionType(filterExpression.getType()); + try { + return FilterAPI.build(topicName, expression, expressionType); + } catch (Exception e) { + throw new ProxyExceptionV2(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); + } + } + + public static Message buildMessage(MessageExt messageExt) { + Map userProperties = buildUserAttributes(messageExt); + SystemProperties systemProperties = buildSystemProperties(messageExt); + Resource topic = buildResource(messageExt.getTopic()); + + return Message.newBuilder() + .setTopic(topic) + .putAllUserProperties(userProperties) + .setSystemProperties(systemProperties) + .setBody(ByteString.copyFrom(messageExt.getBody())) + .build(); + } + + protected static Map buildUserAttributes(MessageExt messageExt) { + Map userAttributes = new HashMap<>(); + Map properties = messageExt.getProperties(); + + for (Map.Entry property : properties.entrySet()) { + if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { + userAttributes.put(property.getKey(), property.getValue()); + } + } + + return userAttributes; + } + + protected static SystemProperties buildSystemProperties(MessageExt messageExt) { + SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); + + // tag + String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); + if (tag != null) { + systemPropertiesBuilder.setTag(tag); + } + + // keys + String keys = messageExt.getKeys(); + if (keys != null) { + String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); + systemPropertiesBuilder.addAllKeys(Arrays.asList(keysArray)); + } + + // message_id + String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); + if (uniqKey != null) { + systemPropertiesBuilder.setMessageId(uniqKey); + } + + // body_digest & body_encoding + String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); + Digest digest = Digest.newBuilder() + .setType(DigestType.MD5) + .setChecksum(md5Result) + .build(); + systemPropertiesBuilder.setBodyDigest(digest); + + if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { + systemPropertiesBuilder.setBodyEncoding(Encoding.GZIP); + } else { + systemPropertiesBuilder.setBodyEncoding(Encoding.IDENTITY); + } + + // message_type + String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + String isTransValue = "true"; + if (isTransValue.equals(isTrans)) { + systemPropertiesBuilder.setMessageType(MessageType.TRANSACTION); + } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + systemPropertiesBuilder.setMessageType(MessageType.DELAY); + } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { + systemPropertiesBuilder.setMessageType(MessageType.FIFO); + } else { + systemPropertiesBuilder.setMessageType(MessageType.NORMAL); + } + + // born_timestamp (millis) + long bornTimestamp = messageExt.getBornTimestamp(); + systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); + + // born_host + systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); + + // store_timestamp (millis) + long storeTimestamp = messageExt.getStoreTimestamp(); + systemPropertiesBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); + + // store_host + SocketAddress storeHost = messageExt.getStoreHost(); + if (storeHost != null) { + systemPropertiesBuilder.setStoreHost(storeHost.toString()); + } + + // delay_level + // TODO: delete +// String delayLevel = messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL); +// if (delayLevel != null) { +// systemAttributeBuilder.setDelayLevel(Integer.parseInt(delayLevel)); +// } + + // delivery_timestamp + String deliverMsString; + long deliverMs; + if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); + deliverMs = System.currentTimeMillis() + delayMs; + systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } else { + deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); + if (deliverMsString != null) { + deliverMs = Long.parseLong(deliverMsString); + systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } + } + + // sharding key + String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + if (shardingKey != null) { + systemPropertiesBuilder.setMessageGroup(shardingKey); + } + + // receipt_handle && invisible_period + ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); + if (receiptHandle != null) { + systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); + } + + // partition_id + systemPropertiesBuilder.setQueueId(messageExt.getQueueId()); + + // partition_offset + systemPropertiesBuilder.setQueueOffset(messageExt.getQueueOffset()); + + // delivery_attempt + systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); + + // publisher_group + // TODO: delete +// String producerGroup = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); +// if (producerGroup != null) { +// systemAttributeBuilder.setProducerGroup(buildResource(producerGroup)); +// } + + // trace context + String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); + if (traceContext != null) { + systemPropertiesBuilder.setTraceContext(traceContext); + } + + return systemPropertiesBuilder.build(); + } + + public static int buildTransactionCommitOrRollback(TransactionResolution type) { + switch (type) { + case COMMIT: + return MessageSysFlag.TRANSACTION_COMMIT_TYPE; + case ROLLBACK: + return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; + default: + return MessageSysFlag.TRANSACTION_NOT_TYPE; + } + } + + public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { + ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); + switch (request.getStatus().getCode().getNumber()) { + case Code.OK_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); + break; + } + case Code.FAILED_TO_CONSUME_MESSAGE_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); + break; + } + case Code.MESSAGE_CORRUPTED_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); + break; + } + } + consumeMessageDirectlyResult.setRemark("From gRPC client"); + return consumeMessageDirectlyResult; + } + + public static Resource buildResource(String resourceNameWithNamespace) { + return Resource.newBuilder() + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) + .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) + .build(); + } + + public static long buildPollTimeFromContext(Context ctx) { + long timeRemaining = ctx.getDeadline() + .timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + + return pollTime; + } + +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java new file mode 100644 index 0000000000..12ead80221 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.adapter; + +import apache.rocketmq.v2.Code; + +public class ProxyExceptionV2 extends RuntimeException { + + private final Code code; + + public ProxyExceptionV2(Code code, String errorMessage) { + super(errorMessage); + this.code = code; + } + + public ProxyExceptionV2(Code code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + public Code getCode() { + return code; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java new file mode 100644 index 0000000000..e9f64f88a9 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java @@ -0,0 +1,112 @@ +/* + * 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.grpc.adapter; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Status; +import org.apache.rocketmq.common.protocol.ResponseCode; + +public class ResponseBuilderV2 { + + public static Status buildStatus(Code code, String message) { + return Status.newBuilder() + .setCode(code) + .setMessage(message) + .build(); + } + + public static Status buildStatus(int remotingResponseCode, String remark) { + return Status.newBuilder() + .setCode(buildCode(remotingResponseCode)) + .setMessage(remark) + .build(); + } + + public static Code buildCode(int remotingResponseCode) { + Code code; + switch (remotingResponseCode) { + case ResponseCode.SUCCESS: + case ResponseCode.NO_MESSAGE: { + code = Code.OK; + break; + } + case ResponseCode.SYSTEM_ERROR: { + code = Code.INTERNAL_SERVER_ERROR; + break; + } + case ResponseCode.SYSTEM_BUSY: + case ResponseCode.POLLING_FULL: { + code = Code.TOO_MANY_REQUESTS; + break; + } + case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { + code = Code.NOT_IMPLEMENTED; + break; + } + case ResponseCode.MESSAGE_ILLEGAL: + case ResponseCode.VERSION_NOT_SUPPORTED: + case ResponseCode.SUBSCRIPTION_PARSE_FAILED: + case ResponseCode.FILTER_DATA_NOT_EXIST: { + code = Code.INVALID_ARGUMENT; + break; + } + case ResponseCode.SERVICE_NOT_AVAILABLE: + case ResponseCode.SLAVE_NOT_AVAILABLE: + case ResponseCode.PULL_RETRY_IMMEDIATELY: + case ResponseCode.PULL_OFFSET_MOVED: + case ResponseCode.SUBSCRIPTION_NOT_LATEST: + case ResponseCode.FILTER_DATA_NOT_LATEST: { + code = Code.UNAVAILABLE; + break; + } + case ResponseCode.NO_PERMISSION: { + code = Code.PERMISSION_DENIED; + break; + } + case ResponseCode.TOPIC_NOT_EXIST: + code = Code.TOPIC_NOT_FOUND; + break; + case ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST: + case ResponseCode.SUBSCRIPTION_NOT_EXIST: + case ResponseCode.PULL_NOT_FOUND: + case ResponseCode.QUERY_NOT_FOUND: + case ResponseCode.CONSUMER_NOT_ONLINE: { + code = Code.NOT_FOUND; + break; + } + case ResponseCode.POLLING_TIMEOUT: + case ResponseCode.FLUSH_DISK_TIMEOUT: + case ResponseCode.FLUSH_SLAVE_TIMEOUT: { + code = Code.DEADLINE_EXCEEDED; + break; + } + default: { + code = Code.INTERNAL_SERVER_ERROR; + } + + } + return code; + } + + public static String buildMessage(int responseCode, String remark) { + if (remark != null) { + return "ResponseCode: " + responseCode + " " + remark; + } + return "ResponseCode: " + responseCode; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index 73578a39d7..04d5137e14 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -65,4 +65,7 @@ public class InterceptorConstants { public static final Metadata.Key SESSION_TOKEN = Metadata.Key.of("x-mq-session-token", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key CLIENT_ID + = Metadata.Key.of("x-mq-client-id", Metadata.ASCII_STRING_MARSHALLER); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index 752e54add3..e6407d6f6a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -109,7 +109,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return this.routeService.queryRoute(ctx, request); + return null; } @Override @@ -133,12 +133,12 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - return this.producerService.sendMessage(ctx, request); + return null; } @Override public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return this.routeService.queryAssignment(ctx, request); + return null; } @Override @@ -159,7 +159,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return this.producerService.forwardMessageToDeadLetterQueue(ctx, request); + return null; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java new file mode 100644 index 0000000000..6bc4d9943e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java @@ -0,0 +1,181 @@ +/* + * 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.grpc.service; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; +import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ForwardClientService; +import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; +import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; +import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements GrpcForwardServiceV2 { + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread")); + + private final ChannelManager channelManager; + private final ConnectorManager connectorManager; + private final ProducerService producerService; + private final ConsumerService receiveMessageService; + private final RouteService routeService; + private final ForwardClientService clientService; + private final PullMessageService pullMessageService; + private final TransactionService transactionService; + private final PollResponseManager pollCommandResponseManager; + + public ClusterGrpcServiceV2() { + this.channelManager = new ChannelManager(); + this.pollCommandResponseManager = new PollResponseManager(); + this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); + this.receiveMessageService = new ConsumerService(connectorManager); + this.producerService = new ProducerService(connectorManager); + this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); + this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); + this.pullMessageService = new PullMessageService(connectorManager); + this.transactionService = new TransactionService(connectorManager, channelManager); + + this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); + this.appendStartAndShutdown(this.connectorManager); + } + + @Override + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + return null; + } + + @Override + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + return null; + } + + @Override + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + return null; + } + + @Override + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + return null; + } + + @Override + public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + return null; + } + + @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + return null; + } + + @Override + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + return null; + } + + @Override + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + return null; + } + + @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { + return null; + } + + @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { + return null; + } + + @Override public CompletableFuture telemetry(Context ctx, TelemetryCommand request) { + return null; + } + + @Override public CompletableFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request) { + return null; + } + + @Override public CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + return null; + } + + private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { + + @Override + public void start() throws Exception { + + } + + @Override + public void shutdown() throws Exception { + scheduledExecutorService.shutdown(); + } + } + + private class GrpcTransactionStateChecker implements TransactionStateChecker { + + @Override + public void checkTransactionState(TransactionStateCheckRequest checkData) { + transactionService.checkTransactionState(checkData); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java new file mode 100644 index 0000000000..e5d6dc8115 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.service; + +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; + +public class GrpcClientManager { + + private static final Map CLIENT_DATAS = new ConcurrentHashMap<>(); + + public static Settings getClientSettings(Context ctx) { + return CLIENT_DATAS.get(getClientId(ctx)).settings; + } + + public static void updateClientData(Context ctx, Settings settings, StreamObserver responseStreamObserver) { + CLIENT_DATAS.put(getClientId(ctx), new ClientData(settings, responseStreamObserver)); + } + + public static String getClientId(Context ctx) { + return InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + } + + public static class ClientData { + private final Settings settings; + private final StreamObserver responseStreamObserver; + + public ClientData(Settings settings, + StreamObserver responseStreamObserver) { + this.settings = settings; + this.responseStreamObserver = responseStreamObserver; + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java new file mode 100644 index 0000000000..aaa785e415 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java @@ -0,0 +1,76 @@ +/* + * 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.grpc.service; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.common.StartAndShutdown; + +public interface GrpcForwardServiceV2 extends StartAndShutdown { + + CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); + + CompletableFuture heartbeat(Context ctx, HeartbeatRequest request); + + CompletableFuture sendMessage(Context ctx, SendMessageRequest request); + + CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); + + CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request); + + CompletableFuture ackMessage(Context ctx, AckMessageRequest request); + + CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); + + CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); + + CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request); + + CompletableFuture pullMessage(Context ctx, PullMessageRequest request); + + CompletableFuture telemetry(Context ctx, TelemetryCommand request); + + CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); + + CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java index fb2422736d..b92a261304 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java @@ -16,7 +16,7 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentRequest; import io.grpc.Context; import java.util.List; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java index 61857f4bf9..3be08632a0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java @@ -16,15 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.FilterExpression; -import apache.rocketmq.v1.Resource; -import com.google.rpc.Code; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.Resource; import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; public class BaseService { @@ -37,25 +37,25 @@ public class BaseService { protected ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); if (receiptHandle.isExpired()) { - throw new ProxyException(Code.INVALID_ARGUMENT, "handle has expired"); + throw new ProxyExceptionV2(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); } return receiptHandle; } protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { if (StringUtils.isBlank(brokerName)) { - throw new ProxyException(Code.INVALID_ARGUMENT, "broker name is empty"); + throw new ProxyExceptionV2(Code.INVALID_ARGUMENT, "broker name is empty"); } String addr = this.connectorManager.getTopicRouteCache().getBrokerAddr(brokerName); if (StringUtils.isBlank(addr)) { - throw new ProxyException(Code.NOT_FOUND, brokerName + " not exist"); + throw new ProxyExceptionV2(Code.NOT_FOUND, brokerName + " not exist"); } return addr; } protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { // for checking filterExpression. - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcConverter.buildSubscriptionData(topicName, filterExpression); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); + GrpcConverterV2.buildSubscriptionData(topicName, filterExpression); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index c82d658b45..6129bd2b33 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -16,14 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import com.google.rpc.Code; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; import java.util.List; @@ -47,10 +48,11 @@ import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { @@ -66,7 +68,7 @@ public class ConsumerService extends BaseService { private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackNoMatchedMessageHook; private volatile ResponseHook ackMessageHook; - private volatile ResponseHook nackMessageHook; + private volatile ResponseHook changeInvisibleDurationMessageHook; public ConsumerService(ConnectorManager connectorManager) { super(connectorManager); @@ -92,7 +94,7 @@ public class ConsumerService extends BaseService { SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); if (messageQueue == null) { - throw new ProxyException(Code.NOT_FOUND, "no readable topic route for topic " + requestHeader.getTopic()); + throw new ProxyExceptionV2(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); } CompletableFuture popResultFuture = this.readConsumer.popMessage( @@ -119,8 +121,8 @@ public class ConsumerService extends BaseService { } protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { - checkSubscriptionData(request.getPartition().getTopic(), request.getFilterExpression()); - return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); + checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); + return GrpcConverterV2.buildPopMessageRequestHeader(request, GrpcConverterV2.buildPollTimeFromContext(ctx)); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { @@ -128,25 +130,25 @@ public class ConsumerService extends BaseService { switch (status) { case FOUND: return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .addAllMessages(checkAndGetMessagesFromPopResult(ctx, request, result)) .build(); case POLLING_FULL: return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.RESOURCE_EXHAUSTED, "polling full")) + .setStatus(ResponseBuilderV2.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) .build(); case NO_NEW_MSG: case POLLING_NOT_FOUND: default: return ReceiveMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, "no new message")) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "no new message")) .build(); } } protected List checkAndGetMessagesFromPopResult(Context ctx, ReceiveMessageRequest request, PopResult result) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SubscriptionData subscriptionData = GrpcConverterV2.buildSubscriptionData(topicName, request.getFilterExpression()); List messages = new ArrayList<>(); for (MessageExt messageExt : result.getMsgFoundList()) { @@ -154,7 +156,7 @@ public class ConsumerService extends BaseService { this.ackNoMatchedMessage(ctx, request, messageExt); continue; } - messages.add(GrpcConverter.buildMessage(messageExt)); + messages.add(GrpcConverterV2.buildMessage(messageExt)); } return messages; @@ -170,7 +172,7 @@ public class ConsumerService extends BaseService { return; } String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); - ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); + ackMessageRequestHeader.setConsumerGroup(GrpcConverterV2.wrapResourceWithNamespace(request.getGroup())); ackMessageRequestHeader.setTopic(messageExt.getTopic()); ackMessageRequestHeader.setQueueId(handle.getQueueId()); ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); @@ -222,31 +224,32 @@ public class ConsumerService extends BaseService { } protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request) { - return GrpcConverter.buildAckMessageRequestHeader(request); + return GrpcConverterV2.buildAckMessageRequestHeader(request); } protected AckMessageResponse convertToAckMessageResponse(Context ctx, AckMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return AckMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .build(); } return AckMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "ack failed: status is abnormal")) + .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) .build(); } - public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); + public CompletableFuture nackMessage(Context ctx, ChangeInvisibleDurationRequest request) { + CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { - if (nackMessageHook != null) { - nackMessageHook.beforeResponse(ctx, request, response, throwable); + if (changeInvisibleDurationMessageHook != null) { + changeInvisibleDurationMessageHook.beforeResponse(ctx, request, response, throwable); } }); try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); + Settings settings = GrpcClientManager.getClientSettings(ctx); if (request.getDeliveryAttempt() >= request.getMaxDeliveryAttempts()) { CompletableFuture resultFuture = this.producer.sendMessageBack( brokerAddr, @@ -287,28 +290,28 @@ public class ConsumerService extends BaseService { return future; } - protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); + protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, ChangeInvisibleDurationRequest request) { + return GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } - protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request); + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, ChangeInvisibleDurationRequest request) { + return GrpcConverterV2.buildConsumerSendMsgBackToDLQRequestHeader(request); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setCommon(ResponseBuilderV2.buildCommon(Code.OK, Code.OK.name())) .build(); } return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) + .setCommon(ResponseBuilderV2.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) .build(); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, RemotingCommand sendMsgBackToDLQResult) { return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) + .setCommon(ResponseBuilderV2.buildCommon(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) .build(); } @@ -327,8 +330,4 @@ public class ConsumerService extends BaseService { public void setAckMessageHook(ResponseHook ackMessageHook) { this.ackMessageHook = ackMessageHook; } - - public void setNackMessageHook(ResponseHook nackMessageHook) { - this.nackMessageHook = nackMessageHook; - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java index d81f9c92b5..80709fb96a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java @@ -16,13 +16,13 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentRequest; import io.grpc.Context; import java.util.List; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @@ -34,7 +34,7 @@ public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @Override public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topicName); return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java index 284270921c..2acb517abf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java @@ -16,7 +16,7 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; @@ -37,8 +37,8 @@ public class DefaultReadQueueSelector implements ReadQueueSelector { try { String topic = requestHeader.getTopic(); - if (request.hasPartition() && request.getPartition().hasBroker()) { - String brokerName = request.getPartition().getBroker().getName(); + if (request.hasMessageQueue() && request.getMessageQueue().hasBroker()) { + String brokerName = request.getMessageQueue().getBroker().getName(); if (StringUtils.isNotBlank(brokerName)) { messageQueue = topicRouteCache.selectReadBrokerByName(topic, brokerName); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java index 7d91a8233b..0148038266 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java @@ -16,9 +16,11 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; +import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; @@ -40,16 +42,19 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { Context ctx, SendMessageRequest request, SendMessageRequestHeader requestHeader, - org.apache.rocketmq.common.message.Message message + List messageList ) { try { String topic = requestHeader.getTopic(); String brokerName = ""; - if (request.hasPartition()) { - brokerName = request.getPartition().getBroker().getName(); + if (request.hasMessageQueue()) { + brokerName = request.getMessageQueue().getBroker().getName(); } Integer queueId = requestHeader.getQueueId(); - String shardingKey = message.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + String shardingKey = null; + if (messageList.size() == 1) { + shardingKey = messageList.get(0).getProperty(MessageConst.PROPERTY_SHARDING_KEY); + } SelectableMessageQueue targetMessageQueue; if (StringUtils.isNotBlank(brokerName) && queueId != null) { // Grpc client sendSelect situation diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java index 1e23ce167d..30874ed9f3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java @@ -16,13 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import com.google.rpc.Code; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SendReceipt; +import com.beust.jcommander.internal.Lists; import io.grpc.Context; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -34,9 +36,9 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -76,14 +78,14 @@ public class ProducerService extends BaseService { }); try { - Pair requestPair = this.buildSendMessageRequest(ctx, request); + Pair> requestPair = this.buildSendMessageRequest(ctx, request); SendMessageRequestHeader requestHeader = requestPair.getLeft(); - org.apache.rocketmq.common.message.Message message = requestPair.getRight(); + List message = requestPair.getRight(); SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request, requestHeader, message); String topic = requestHeader.getTopic(); if (selectableMessageQueue == null) { - throw new ProxyException(Code.NOT_FOUND, "no writeable topic route for topic: " + topic); + throw new ProxyExceptionV2(Code.FORBIDDEN, "no writeable topic route for topic: " + topic); } // send message to broker. @@ -112,31 +114,30 @@ public class ProducerService extends BaseService { return future; } - protected Pair buildSendMessageRequest( + protected Pair> buildSendMessageRequest( Context ctx, SendMessageRequest request) { - SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request); - org.apache.rocketmq.common.message.Message message = GrpcConverter.buildMessage(request.getMessage()); + String topic = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + // use topic name as group + SendMessageRequestHeader requestHeader = GrpcConverterV2.buildSendMessageRequestHeader(request, topic); + List message = GrpcConverterV2.buildMessage(request.getMessagesList(), topic); return Pair.of(requestHeader, message); } protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult result) { if (result.getSendStatus() != SendStatus.SEND_OK) { return SendMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) .build(); } - if (StringUtils.isNotBlank(result.getTransactionId())) { - Message message = request.getMessage(); - String group = GrpcConverter.wrapResourceWithNamespace(message.getSystemAttribute().getProducerGroup()); - String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); - this.connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(group, topic); - } - - return SendMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + List sendReceiptList = Lists.newArrayList(); + sendReceiptList.add(SendReceipt.newBuilder() .setMessageId(StringUtils.defaultString(result.getMsgId())) - .setTransactionId(StringUtils.defaultString(result.getTransactionId())) // use "" if transactionID is null. + .setTransactionId(StringUtils.defaultString(result.getTransactionId())) + .build()); + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .addAllReceipts(sendReceiptList) .build(); } @@ -158,7 +159,7 @@ public class ProducerService extends BaseService { .thenAccept(result -> future.complete( ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(result.getCode(), result.getRemark())) + .setStatus(ResponseBuilderV2.buildStatus(result.getCode(), result.getRemark())) .build() ) ) @@ -174,6 +175,6 @@ public class ProducerService extends BaseService { protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); + return GrpcConverterV2.buildConsumerSendMsgBackRequestHeader(request); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java index b5b0545e19..48ec46ab9b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java @@ -16,14 +16,14 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; import com.google.protobuf.util.Timestamps; -import com.google.rpc.Code; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -36,8 +36,8 @@ import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class PullMessageService extends BaseService { @@ -62,8 +62,8 @@ public class PullMessageService extends BaseService { }); try { - Partition partition = request.getPartition(); - String topic = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); + MessageQueue partition = request.getMessageQueue(); + String topic = GrpcConverterV2.wrapResourceWithNamespace(partition.getTopic()); String brokerName = partition.getBroker().getName(); int queueId = partition.getId(); @@ -83,7 +83,7 @@ public class PullMessageService extends BaseService { offsetFuture .thenAccept(result -> future.complete( QueryOffsetResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .setOffset(result) .build())) .exceptionally(throwable -> { @@ -107,7 +107,7 @@ public class PullMessageService extends BaseService { try { PullMessageRequestHeader requestHeader = this.buildPullMessageRequestHeader(ctx, request); - String brokerName = request.getPartition().getBroker().getName(); + String brokerName = request.getMessageQueue().getBroker().getName(); String brokerAddr = this.getBrokerAddr(ctx, brokerName); CompletableFuture pullResultFuture = this.readConsumer.pullMessage(brokerAddr, requestHeader); @@ -131,25 +131,25 @@ public class PullMessageService extends BaseService { } protected PullMessageRequestHeader buildPullMessageRequestHeader(Context ctx, PullMessageRequest request) { - checkSubscriptionData(request.getPartition().getTopic(), request.getFilterExpression()); - return GrpcConverter.buildPullMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); + checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); + return GrpcConverterV2.buildPullMessageRequestHeader(request, GrpcConverterV2.buildPollTimeFromContext(ctx)); } protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { PullMessageResponse.Builder responseBuilder = PullMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .setMinOffset(result.getMinOffset()) .setMaxOffset(result.getMaxOffset()) .setNextOffset(result.getNextBeginOffset()); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( - GrpcConverter.wrapResourceWithNamespace(request.getPartition().getTopic()), request.getFilterExpression()); + SubscriptionData subscriptionData = GrpcConverterV2.buildSubscriptionData( + GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), request.getFilterExpression()); PullStatus status = result.getPullStatus(); if (status.equals(PullStatus.FOUND)) { List messageList = result.getMsgFoundList().stream() .filter(msg -> FilterUtils.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. - .map(GrpcConverter::buildMessage) + .map(GrpcConverterV2::buildMessage) .collect(Collectors.toList()); return responseBuilder.addAllMessages(messageList).build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java index cd0702d1c1..4fa9c6e350 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java @@ -16,7 +16,7 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java index 5b48a15d4a..d639a149e7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java @@ -16,21 +16,21 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Address; -import apache.rocketmq.v1.AddressScheme; -import apache.rocketmq.v1.Assignment; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.Permission; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Assignment; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.Permission; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; import com.google.common.base.Preconditions; import com.google.common.net.HostAndPort; -import com.google.rpc.Code; import io.grpc.Context; import java.util.ArrayList; import java.util.HashMap; @@ -46,10 +46,10 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; import org.apache.rocketmq.proxy.grpc.adapter.ParameterConverter; import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; public class RouteService extends BaseService { @@ -100,18 +100,18 @@ public class RouteService extends BaseService { }); try { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); List brokerDataList = topicRouteData.getBrokerDatas(); - List partitionList = new ArrayList<>(); + List messageQueueList = new ArrayList<>(); if (ProxyMode.isClusterMode(mode.name())) { Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + .setStatus(ResponseBuilderV2.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); return future; @@ -123,7 +123,7 @@ public class RouteService extends BaseService { .setEndpoints(resEndpoints) .build(); - partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + messageQueueList.addAll(genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); } } if (ProxyMode.isLocalMode(mode.name())) { @@ -136,20 +136,20 @@ public class RouteService extends BaseService { break; } for (Broker broker : brokerIdMap.values()) { - partitionList.addAll(genPartitionFromQueueData(queueData, request.getTopic(), broker)); + messageQueueList.addAll(genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); } } } QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .addAllPartitions(partitionList) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .addAllMessageQueues(messageQueueList) .build(); future.complete(response); } catch (Throwable t) { if (TopicRouteHelper.isTopicNotExistError(t)) { future.complete(QueryRouteResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.NOT_FOUND, t.getMessage())) + .setStatus(ResponseBuilderV2.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) .build()); } else { future.completeExceptionally(t); @@ -158,8 +158,8 @@ public class RouteService extends BaseService { return future; } - protected static List genPartitionFromQueueData(QueueData queueData, Resource topic, Broker broker) { - List partitionList = new ArrayList<>(); + protected static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { + List messageQueueList = new ArrayList<>(); int r = 0; int w = 0; @@ -177,30 +177,30 @@ public class RouteService extends BaseService { // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. int queueIdIndex = 0; for (int i = 0; i < r; i++) { - Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) .setId(queueIdIndex++) .setPermission(Permission.READ) .build(); - partitionList.add(partition); + messageQueueList.add(messageQueue); } for (int i = 0; i < w; i++) { - Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) .setId(queueIdIndex++) .setPermission(Permission.WRITE) .build(); - partitionList.add(partition); + messageQueueList.add(messageQueue); } for (int i = 0; i < rw; i++) { - Partition partition = Partition.newBuilder().setBroker(broker).setTopic(topic) + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) .setId(queueIdIndex++) .setPermission(Permission.READ_WRITE) .build(); - partitionList.add(partition); + messageQueueList.add(messageQueue); } - return partitionList; + return messageQueueList; } public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { @@ -215,7 +215,7 @@ public class RouteService extends BaseService { List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); if (ProxyMode.isLocalMode(mode)) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); @@ -224,7 +224,7 @@ public class RouteService extends BaseService { if (brokerIdMap != null) { Broker broker = brokerIdMap.get(0L); - Partition defaultPartition = Partition.newBuilder() + MessageQueue defaultMessageQueue = MessageQueue.newBuilder() .setTopic(request.getTopic()) .setId(-1) .setPermission(Permission.READ_WRITE) @@ -232,7 +232,7 @@ public class RouteService extends BaseService { .build(); assignments.add(Assignment.newBuilder() - .setPartition(defaultPartition) + .setMessageQueue(defaultMessageQueue) .build()); } } @@ -241,7 +241,7 @@ public class RouteService extends BaseService { Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.INVALID_ARGUMENT, "endpoint " + + .setStatus(ResponseBuilderV2.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); return future; @@ -253,7 +253,7 @@ public class RouteService extends BaseService { .setEndpoints(resEndpoints) .build(); - Partition defaultPartition = Partition.newBuilder() + MessageQueue defaultMessageQueue = MessageQueue.newBuilder() .setTopic(request.getTopic()) .setId(-1) .setPermission(Permission.READ_WRITE) @@ -261,14 +261,14 @@ public class RouteService extends BaseService { .build(); assignments.add(Assignment.newBuilder() - .setPartition(defaultPartition) + .setMessageQueue(defaultMessageQueue) .build()); } } QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() .addAllAssignments(assignments) - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .build(); future.complete(response); } catch (Throwable t) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java index c55af42501..8c9814f6b9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java @@ -16,12 +16,12 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; -import com.google.rpc.Code; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -34,8 +34,8 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; @@ -45,7 +45,7 @@ public class TransactionService extends BaseService implements TransactionStateC private final ChannelManager channelManager; private final ForwardProducer forwardProducer; - private volatile ResponseHook checkTransactionStateHook; + private volatile ResponseHook checkTransactionStateHook; private volatile ResponseHook endTransactionHook; public TransactionService(ConnectorManager connectorManager, ChannelManager channelManager) { @@ -67,8 +67,8 @@ public class TransactionService extends BaseService implements TransactionStateC GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); String transactionId = checkData.getTransactionId().getProxyTransactionId(); - Message message = GrpcConverter.buildMessage(checkData.getMessageExt()); - PollCommandResponse response = PollCommandResponse.newBuilder() + Message message = GrpcConverterV2.buildMessage(checkData.getMessageExt()); + TelemetryCommand response = TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand( RecoverOrphanedTransactionCommand.newBuilder() .setOrphanedTransactionalMessage(message) @@ -101,7 +101,7 @@ public class TransactionService extends BaseService implements TransactionStateC EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); this.forwardProducer.endTransaction(brokerAddr, requestHeader); future.complete(EndTransactionResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .build()); } catch (Throwable t) { future.completeExceptionally(t); @@ -110,11 +110,13 @@ public class TransactionService extends BaseService implements TransactionStateC } protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { - return GrpcConverter.buildEndTransactionRequestHeader(request); + String topic = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + // use topic name as producerGroup + return GrpcConverterV2.buildEndTransactionRequestHeader(request, topic); } public void setCheckTransactionStateHook( - ResponseHook checkTransactionStateHook) { + ResponseHook checkTransactionStateHook) { this.checkTransactionStateHook = checkTransactionStateHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java index 8605d11062..e1000961e2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java @@ -16,13 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; +import java.util.List; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; public interface WriteQueueSelector { SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, - SendMessageRequestHeader requestHeader, org.apache.rocketmq.common.message.Message message); + SendMessageRequestHeader requestHeader, List messageList); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java index ba059db95f..896c79d36f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java @@ -17,19 +17,19 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; -import apache.rocketmq.v1.Address; -import apache.rocketmq.v1.AddressScheme; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.Permission; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.Permission; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; import com.google.common.net.HostAndPort; -import com.google.rpc.Code; import io.grpc.Context; import java.util.ArrayList; import java.util.HashMap; @@ -95,7 +95,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testGenPartitionFromQueueData() throws Exception { // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. QueueData queueDataWith8R8WPermRW = mockQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); @@ -103,7 +103,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. QueueData queueDataWith8R8WPermR = mockQueueData(8, 8, PermName.PERM_READ); - List partitionWith8R8WPermR = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermR = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermR.size()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -111,7 +111,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. QueueData queueDataWith8R8WPermW = mockQueueData(8, 8, PermName.PERM_WRITE); - List partitionWith8R8WPermW = RouteService.genPartitionFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermW = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -119,7 +119,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. QueueData queueDataWith8R0WPermRW = mockQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R0WPermRW = RouteService.genPartitionFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R0WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R0WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -127,7 +127,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. QueueData queueDataWith4R8WPermRW = mockQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith4R8WPermRW = RouteService.genPartitionFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith4R8WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith4R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(4); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(4); @@ -160,9 +160,9 @@ public class RouteServiceTest extends BaseServiceTest { .build()) .build()); QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(8, response.getPartitionsCount()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getPartitions(0).getBroker() + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); + assertEquals(8, response.getMessageQueuesCount()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getMessageQueues(0).getBroker() .getEndpoints().getAddresses(0).getHost()); } @@ -177,7 +177,7 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryRouteResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.ILLEGAL_ACCESS_POINT.getNumber(), response.getStatus().getCode().getNumber()); } @Test @@ -198,9 +198,9 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals(8, response.getPartitionsCount()); - assertEquals("host", response.getPartitions(0).getBroker() + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); + assertEquals(8, response.getMessageQueuesCount()); + assertEquals("host", response.getMessageQueues(0).getBroker() .getEndpoints().getAddresses(0).getHost()); } @@ -222,7 +222,7 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryRouteResponse response = future.get(); - assertEquals(Code.NOT_FOUND.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.TOPIC_NOT_FOUND.getNumber(), response.getStatus().getCode().getNumber()); } @Test @@ -238,7 +238,7 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryAssignmentResponse response = future.get(); - assertEquals(Code.INVALID_ARGUMENT.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.ILLEGAL_ACCESS_POINT.getNumber(), response.getStatus().getCode().getNumber()); } @Test @@ -263,10 +263,10 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); + assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); } @Test @@ -291,10 +291,10 @@ public class RouteServiceTest extends BaseServiceTest { .build()); QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getPartition().getBroker().getName()); - assertEquals("host", response.getAssignments(0).getPartition().getBroker().getEndpoints().getAddresses(0).getHost()); + assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); + assertEquals("host", response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); } } From 72d2581cf75a85c4e7ddc6e0c5a1d23b598225e9 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 1 Apr 2022 21:04:41 +0800 Subject: [PATCH 084/338] [ISSUE #3949] v2 support --- .../proxy/grpc/GrpcMessagingProcessorV2.java | 15 +++++ .../proxy/grpc/adapter/GrpcConverterV2.java | 39 ++++++------ .../grpc/service/ClusterGrpcService.java | 12 ++-- .../grpc/service/ClusterGrpcServiceV2.java | 59 +++++++++++-------- .../grpc/service/GrpcForwardServiceV2.java | 4 ++ .../grpc/service/cluster/ConsumerService.java | 32 +++++----- 6 files changed, 98 insertions(+), 63 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java index 9315381445..6a282ff55a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java @@ -18,6 +18,8 @@ package org.apache.rocketmq.proxy.grpc; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.HeartbeatResponse; @@ -138,6 +140,19 @@ public class GrpcMessagingProcessorV2 extends MessagingServiceGrpc.MessagingServ }); } + @Override + public void nackMessage(NackMessageRequest request, StreamObserver responseObserver) { + CompletableFuture future = grpcForwardService.nackMessage(Context.current(), request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + NackMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + } + @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java index 41a8e35b80..95a02e786a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java @@ -30,6 +30,7 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; +import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; @@ -178,8 +179,8 @@ public class GrpcConverterV2 { return ackMessageRequestHeader; } - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader( - ChangeInvisibleDurationRequest request) { + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, + DelayPolicy delayPolicy) { String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); @@ -190,10 +191,26 @@ public class GrpcConverterV2 { changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); + changeInvisibleTimeRequestHeader.setInvisibleTime( + delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); return changeInvisibleTimeRequestHeader; } + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(NackMessageRequest request, int maxReconsumeTimes) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); + return consumerSendMsgBackRequestHeader; + } + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( ForwardMessageToDeadLetterQueueRequest request) { String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); @@ -210,22 +227,6 @@ public class GrpcConverterV2 { return consumerSendMsgBackRequestHeader; } - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( - ChangeInvisibleDurationRequest request, String messageId, int maxReconsumeTimes) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); - consumerSendMsgBackRequestHeader.setGroup(groupName); - consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); - consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); - return consumerSendMsgBackRequestHeader; - } - public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, String producerGroup) { String messageId = request.getMessageId(); String transactionId = request.getTransactionId(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java index e6407d6f6a..ce94063d69 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java @@ -143,17 +143,17 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return this.receiveMessageService.receiveMessage(ctx, request); + return null; } @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return this.receiveMessageService.ackMessage(ctx, request); + return null; } @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - return this.receiveMessageService.nackMessage(ctx, request); + return null; } @Override @@ -164,17 +164,17 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - return this.transactionService.endTransaction(ctx, request); + return null; } @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return this.pullMessageService.queryOffset(ctx, request); + return null; } @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return this.pullMessageService.pullMessage(ctx, request); + return null; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java index 6bc4d9943e..fb4593a7c2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcServiceV2.java @@ -27,6 +27,8 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.PullMessageRequest; @@ -74,7 +76,7 @@ public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements Gr private final ChannelManager channelManager; private final ConnectorManager connectorManager; private final ProducerService producerService; - private final ConsumerService receiveMessageService; + private final ConsumerService consumerService; private final RouteService routeService; private final ForwardClientService clientService; private final PullMessageService pullMessageService; @@ -85,7 +87,7 @@ public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements Gr this.channelManager = new ChannelManager(); this.pollCommandResponseManager = new PollResponseManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); - this.receiveMessageService = new ConsumerService(connectorManager); + this.consumerService = new ConsumerService(connectorManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); @@ -98,7 +100,7 @@ public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements Gr @Override public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return null; + return routeService.queryRoute(ctx, request); } @Override @@ -108,52 +110,63 @@ public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements Gr @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - return null; + return producerService.sendMessage(ctx, request); } @Override public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return null; + return routeService.queryAssignment(ctx, request); } @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return null; + return consumerService.receiveMessage(ctx, request); } - @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return null; + @Override + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { + return consumerService.nackMessage(ctx, request); + } + + @Override + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + return consumerService.ackMessage(ctx, request); } @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return null; + return producerService.forwardMessageToDeadLetterQueue(ctx, request); } @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + return transactionService.endTransaction(ctx, request); + } + + @Override + public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { + return pullMessageService.queryOffset(ctx, request); + } + + @Override + public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { + return pullMessageService.pullMessage(ctx, request); + } + + @Override + public CompletableFuture telemetry(Context ctx, TelemetryCommand request) { return null; } - @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return null; - } - - @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return null; - } - - @Override public CompletableFuture telemetry(Context ctx, TelemetryCommand request) { - return null; - } - - @Override public CompletableFuture notifyClientTermination(Context ctx, + @Override + public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { return null; } - @Override public CompletableFuture changeInvisibleDuration(Context ctx, + @Override + public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java index aaa785e415..dbbe9f813c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java @@ -27,6 +27,8 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.PullMessageRequest; @@ -58,6 +60,8 @@ public interface GrpcForwardServiceV2 extends StartAndShutdown { CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request); + CompletableFuture nackMessage(Context ctx, NackMessageRequest request); + CompletableFuture ackMessage(Context ctx, AckMessageRequest request); CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java index 6129bd2b33..a2f7b34e8e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java @@ -18,10 +18,10 @@ package org.apache.rocketmq.proxy.grpc.service.cluster; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Settings; @@ -68,7 +68,7 @@ public class ConsumerService extends BaseService { private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackNoMatchedMessageHook; private volatile ResponseHook ackMessageHook; - private volatile ResponseHook changeInvisibleDurationMessageHook; + private volatile ResponseHook nackMessageResponseResponseHook; public ConsumerService(ConnectorManager connectorManager) { super(connectorManager); @@ -238,11 +238,11 @@ public class ConsumerService extends BaseService { .build(); } - public CompletableFuture nackMessage(Context ctx, ChangeInvisibleDurationRequest request) { - CompletableFuture future = new CompletableFuture<>(); + public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { + CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { - if (changeInvisibleDurationMessageHook != null) { - changeInvisibleDurationMessageHook.beforeResponse(ctx, request, response, throwable); + if (nackMessageResponseResponseHook != null) { + nackMessageResponseResponseHook.beforeResponse(ctx, request, response, throwable); } }); try { @@ -250,10 +250,11 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); Settings settings = GrpcClientManager.getClientSettings(ctx); - if (request.getDeliveryAttempt() >= request.getMaxDeliveryAttempts()) { + int maxDeliveryAttempts = settings.getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); + if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( brokerAddr, - this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request) + this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts) ); resultFuture @@ -290,28 +291,29 @@ public class ConsumerService extends BaseService { return future; } - protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, ChangeInvisibleDurationRequest request) { + protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { return GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } - protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, ChangeInvisibleDurationRequest request) { - return GrpcConverterV2.buildConsumerSendMsgBackToDLQRequestHeader(request); + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request, + int maxReconsumeTimes) { + return GrpcConverterV2.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilderV2.buildCommon(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) .build(); } return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilderV2.buildCommon(Code.INTERNAL, "nack failed: status is abnormal")) + .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "nack failed: status is abnormal")) .build(); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, RemotingCommand sendMsgBackToDLQResult) { return NackMessageResponse.newBuilder() - .setCommon(ResponseBuilderV2.buildCommon(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) + .setStatus(ResponseBuilderV2.buildStatus(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) .build(); } From f0edf9964f3187899fcb46b147e6e10614c5c314 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 6 Apr 2022 10:43:03 +0800 Subject: [PATCH 085/338] [ISSUE #3949] Support v2 for LocalGrpcService --- .../proxy/grpc/adapter/GrpcConverterV2.java | 104 +++++- .../proxy/grpc/adapter/ResponseBuilderV2.java | 3 +- .../adapter/channel/PullMessageChannel.java | 4 +- .../channel/ReceiveMessageChannel.java | 4 +- .../adapter/channel/SendMessageChannel.java | 4 +- .../handler/PullMessageResponseHandler.java | 12 +- .../ReceiveMessageResponseHandler.java | 27 +- .../handler/SendMessageResponseHandler.java | 30 +- .../proxy/grpc/service/GrpcClientManager.java | 18 +- .../grpc/service/GrpcForwardServiceV2.java | 5 +- .../proxy/grpc/service/LocalGrpcService.java | 335 ++++++++---------- 11 files changed, 313 insertions(+), 233 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java index 95a02e786a..e48f062183 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java @@ -18,7 +18,8 @@ package org.apache.rocketmq.proxy.grpc.adapter; import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Digest; import apache.rocketmq.v2.DigestType; @@ -27,10 +28,12 @@ import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; @@ -58,6 +61,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; import org.apache.rocketmq.common.filter.FilterAPI; @@ -75,6 +79,10 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; @@ -92,7 +100,67 @@ public class GrpcConverterV2 { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); } - public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, String producerGroup) { + public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, + ClientSettings clientSettings) { + HeartbeatData heartbeatData = new HeartbeatData(); + heartbeatData.setClientID(clientId); + String groupName = wrapResourceWithNamespace(request.getGroup()); + switch (clientSettings.getClientType()) { + case PRODUCER: { + Set producerDataSet = new HashSet<>(); + producerDataSet.add(buildProducerData(groupName)); + heartbeatData.setProducerDataSet(producerDataSet); + break; + } + case PULL_CONSUMER: + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: { + Set consumerDataSet = new HashSet<>(); + consumerDataSet.add(buildConsumerData(groupName, clientSettings)); + heartbeatData.setConsumerDataSet(consumerDataSet); + break; + } + } + return heartbeatData; + } + + public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(String groupName) { + org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData + = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); + buildProducerData.setGroupName(groupName); + return buildProducerData; + } + + public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, + ClientSettings clientSettings) { + org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); + buildConsumerData.setGroupName(groupName); + buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); + + buildConsumerData.setMessageModel(MessageModel.CLUSTERING); + buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); + Set subscriptionDataSet = + buildSubscriptionDataSet(clientSettings.getSettings() + .getSubscription() + .getSubscriptionsList()); + buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); + return buildConsumerData; + } + + public static ConsumeType buildConsumeType(ClientType clientType) { + switch (clientType) { + case PULL_CONSUMER: + case SIMPLE_CONSUMER: + return ConsumeType.CONSUME_ACTIVELY; + case PUSH_CONSUMER: + return ConsumeType.CONSUME_PASSIVELY; + default: + throw new IllegalArgumentException("Client type is not consumer, type: " + clientType); + } + } + + public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, + String producerGroup) { SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); MessageQueue messageQueue = request.getMessageQueue(); @@ -100,6 +168,9 @@ public class GrpcConverterV2 { if (request.getMessagesCount() <= 0) { throw new ProxyExceptionV2(Code.MESSAGE_CORRUPTED, "no message to send"); } + if (request.getMessagesCount() > 1) { + requestHeader.setBatch(true); + } Message message = request.getMessages(0); SystemProperties systemProperties = message.getSystemProperties(); @@ -227,7 +298,8 @@ public class GrpcConverterV2 { return consumerSendMsgBackRequestHeader; } - public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, String producerGroup) { + public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, + String producerGroup) { String messageId = request.getMessageId(); String transactionId = request.getTransactionId(); TransactionId handle; @@ -253,7 +325,8 @@ public class GrpcConverterV2 { return endTransactionRequestHeader; } - public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { + public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, + long pollTimeoutInMillis) { MessageQueue messageQueue = request.getMessageQueue(); String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverterV2.wrapResourceWithNamespace(messageQueue.getTopic()); @@ -278,6 +351,26 @@ public class GrpcConverterV2 { return requestHeader; } + public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, + ClientType clientType, NotifyClientTerminationRequest request) { + UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + header.setClientID(clientId); + switch (clientType) { + case PRODUCER: { + header.setProducerGroup(groupName); + break; + } + case PULL_CONSUMER: + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: { + header.setConsumerGroup(groupName); + break; + } + } + return header; + } + public static Map buildMessageProperty(Message message, String producerGroup) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties @@ -344,7 +437,8 @@ public class GrpcConverterV2 { return messageWithHeader.getProperties(); } - public static List buildMessage(List protoMessageList, String producerGroup) { + public static List buildMessage(List protoMessageList, + String producerGroup) { List messages = new ArrayList<>(); for (Message protoMessage : protoMessageList) { messages.add(buildMessage(protoMessage, producerGroup)); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java index e9f64f88a9..dc99e0e75d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java @@ -22,7 +22,6 @@ import apache.rocketmq.v2.Status; import org.apache.rocketmq.common.protocol.ResponseCode; public class ResponseBuilderV2 { - public static Status buildStatus(Code code, String message) { return Status.newBuilder() .setCode(code) @@ -55,7 +54,7 @@ public class ResponseBuilderV2 { break; } case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { - code = Code.NOT_IMPLEMENTED; + code = Code.UNRECOGNIZED; break; } case ResponseCode.MESSAGE_ILLEGAL: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java index 533bea1810..ae3fa27daf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java index 934b049b78..860502391b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java index 3eeb98f1ec..d8cc965a0c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.grpc.adapter.channel; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java index 7344d5f451..18495e295f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java @@ -17,17 +17,17 @@ package org.apache.rocketmq.proxy.grpc.adapter.handler; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; import java.nio.ByteBuffer; import java.util.List; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class PullMessageResponseHandler implements ResponseHandler { @@ -41,10 +41,10 @@ public class PullMessageResponseHandler implements ResponseHandler msgFoundList = MessageDecoder.decodes(byteBuffer); for (MessageExt messageExt : msgFoundList) { - builder.addMessages(GrpcConverter.buildMessage(messageExt)); + builder.addMessages(GrpcConverterV2.buildMessage(messageExt)); } } - PullMessageResponse response = builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())) + PullMessageResponse response = builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) .setMinOffset(responseHeader.getMinOffset()) .setNextOffset(responseHeader.getNextBeginOffset()) .setMaxOffset(responseHeader.getMaxOffset()) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java index 9684261673..6b5cf9bc46 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java @@ -17,9 +17,9 @@ package org.apache.rocketmq.proxy.grpc.adapter.handler; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; import com.google.common.base.Stopwatch; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; @@ -36,9 +36,9 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; import org.slf4j.Logger; @@ -46,6 +46,11 @@ import org.slf4j.LoggerFactory; public class ReceiveMessageResponseHandler implements ResponseHandler { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final boolean fifo; + + public ReceiveMessageResponseHandler(boolean fifo) { + this.fifo = fifo; + } @Override public void handle(RemotingCommand responseCommand, @@ -53,14 +58,14 @@ public class ReceiveMessageResponseHandler implements ResponseHandler future = context.getResponse(); - String brokerName = request.getPartition().getBroker().getName(); + String brokerName = request.getMessageQueue().getBroker().getName(); long currentTimeInMillis = System.currentTimeMillis(); long popCosts = currentTimeInMillis - context.getTimestamp(); try { Stopwatch stopWatch = Stopwatch.createStarted(); ReceiveMessageResponse.Builder builder = ReceiveMessageResponse.newBuilder(); PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) responseCommand.readCustomHeader(); - builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); builder.setInvisibleDuration(Durations.fromMillis(responseHeader.getInvisibleTime())) .setDeliveryTimestamp(Timestamps.fromMillis(responseHeader.getPopTime())); @@ -113,7 +118,7 @@ public class ReceiveMessageResponseHandler implements ResponseHandler 0) { messageExt.setReconsumeTimes(count); @@ -121,9 +126,9 @@ public class ReceiveMessageResponseHandler implements ResponseHandler { - private final String messageId; - - public SendMessageResponseHandler(String messageId) { - this.messageId = messageId; + public SendMessageResponseHandler() { } @Override public void handle(RemotingCommand responseCommand, @@ -36,9 +36,19 @@ public class SendMessageResponseHandler implements ResponseHandler CLIENT_DATAS = new ConcurrentHashMap<>(); + private static final Map CLIENT_DATA = new ConcurrentHashMap<>(); - public static Settings getClientSettings(Context ctx) { - return CLIENT_DATAS.get(getClientId(ctx)).settings; + public static ClientSettings getClientSettings(Context ctx) { + return CLIENT_DATA.get(getClientId(ctx)).clientSettings; } - public static void updateClientData(Context ctx, Settings settings, StreamObserver responseStreamObserver) { - CLIENT_DATAS.put(getClientId(ctx), new ClientData(settings, responseStreamObserver)); + public static void updateClientData(Context ctx, ClientSettings clientSettings, StreamObserver responseStreamObserver) { + CLIENT_DATA.put(getClientId(ctx), new ClientData(clientSettings, responseStreamObserver)); } public static String getClientId(Context ctx) { @@ -42,12 +42,12 @@ public class GrpcClientManager { } public static class ClientData { - private final Settings settings; + private final ClientSettings clientSettings; private final StreamObserver responseStreamObserver; - public ClientData(Settings settings, + public ClientData(ClientSettings clientSettings, StreamObserver responseStreamObserver) { - this.settings = settings; + this.clientSettings = clientSettings; this.responseStreamObserver = responseStreamObserver; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java index dbbe9f813c..0e58a68188 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java @@ -43,7 +43,6 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -64,6 +63,8 @@ public interface GrpcForwardServiceV2 extends StartAndShutdown { CompletableFuture ackMessage(Context ctx, AckMessageRequest request); + CompletableFuture nackMessage(Context ctx, NackMessageRequest request); + CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); @@ -72,8 +73,6 @@ public interface GrpcForwardServiceV2 extends StartAndShutdown { CompletableFuture pullMessage(Context ctx, PullMessageRequest request); - CompletableFuture telemetry(Context ctx, TelemetryCommand request); - CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index b562c15132..b7c1841313 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -17,49 +17,39 @@ package org.apache.rocketmq.proxy.grpc.service; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HealthCheckResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NoopCommand; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.NotifyClientTerminationResponse; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryOffsetPolicy; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; -import apache.rocketmq.v1.ReportThreadStackTraceRequest; -import apache.rocketmq.v1.ReportThreadStackTraceResponse; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryOffsetPolicy; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; import com.google.protobuf.util.Timestamps; -import com.google.rpc.Code; import io.grpc.Context; import io.netty.channel.Channel; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -69,10 +59,10 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; @@ -91,11 +81,11 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseFuture; import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; @@ -105,14 +95,12 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHand import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; -import org.apache.rocketmq.remoting.RemotingServer; -import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { +public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardServiceV2 { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final BrokerController brokerController; @@ -145,26 +133,15 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo LanguageCode languageCode; String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); languageCode = LanguageCode.valueOf(language); - HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(request); + String clientId = GrpcClientManager.getClientId(ctx); + + ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + HeartbeatData heartbeatData = GrpcConverterV2.buildHeartbeatData(clientId, request, clientSettings); CompletableFuture future = new CompletableFuture<>(); - String groupName; - switch (request.getClientDataCase()) { - case PRODUCER_DATA: { - groupName = GrpcConverter.wrapResourceWithNamespace(request.getProducerData().getGroup()); - break; - } - case CONSUMER_DATA: { - groupName = GrpcConverter.wrapResourceWithNamespace(request.getConsumerData().getGroup()); - break; - } - default: { - future.completeExceptionally(new IllegalArgumentException("Wrong client data type")); - return future; - } - } + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, request.getClientId(), pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -174,29 +151,26 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand response = this.brokerController.getClientManageProcessor() .heartBeat(simpleChannelHandlerContext, command); - HeartbeatResponse heartbeatResponse = ResponseBuilder.buildHeartbeatResponse(response); + HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) + .build(); future.complete(heartbeatResponse); return future; } - @Override - public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { - log.trace("Received health check request from client: {}", request.getClientHost()); - final HealthCheckResponse response = HealthCheckResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) - .build(); - return CompletableFuture.completedFuture(response); - } - @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SendMessageRequestHeader requestHeader = GrpcConverterV2.buildSendMessageRequestHeader(request, topicName); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); - Message message = request.getMessage(); - command.setBody(message.getBody().toByteArray()); + List messageList = GrpcConverterV2.buildMessage(request.getMessagesList(), topicName); + MessageBatch messageBatch = MessageBatch.generateFromList(messageList); + MessageClientIDSetter.setUniqID(messageBatch); + messageBatch.setBody(messageBatch.encode()); + command.setBody(messageBatch.encode()); command.makeCustomHeaderToNet(); - SendMessageResponseHandler handler = new SendMessageResponseHandler(message.getSystemAttribute().getMessageId()); + SendMessageResponseHandler handler = new SendMessageResponseHandler(); SendMessageChannel channel = channelManager.createChannel(() -> new SendMessageChannel(handler), SendMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -225,12 +199,13 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); - PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); + long pollTime = GrpcConverterV2.buildPollTimeFromContext(ctx); + ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + PopMessageRequestHeader requestHeader = GrpcConverterV2.buildPopMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); - ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(); + ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(clientSettings.getSettings().getSubscription().getFifo()); ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -255,7 +230,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request); + AckMessageRequestHeader requestHeader = GrpcConverterV2.buildAckMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -264,11 +239,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand responseCommand = brokerController.getAckMessageProcessor() .processRequest(channelHandlerContext, command); AckMessageResponse.Builder builder = AckMessageResponse.newBuilder(); - if (null != responseCommand) { - builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); - } else { - builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); - } + builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); AckMessageResponse response = builder.build(); future.complete(response); } catch (Exception e) { @@ -282,7 +253,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -291,7 +262,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() .processRequest(channelHandlerContext, command); NackMessageResponse response = NackMessageResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())) + .setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) .build(); future.complete(response); } catch (Exception e) { @@ -307,7 +278,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); + ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverterV2.buildConsumerSendMsgBackRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); command.makeCustomHeaderToNet(); @@ -317,7 +288,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(response.getCode(), response.getRemark())) + .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) .build()); } catch (Exception e) { log.error("Exception raised when forwardMessageToDeadLetterQueue", e); @@ -331,7 +302,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + EndTransactionRequestHeader requestHeader = GrpcConverterV2.buildEndTransactionRequestHeader(request, topicName); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); command.makeCustomHeaderToNet(); @@ -341,9 +313,9 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); if (null != responseCommand) { - builder.setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); } else { - builder.setCommon(ResponseBuilder.buildCommon(Code.INTERNAL, "Response command is null")); + builder.setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); } EndTransactionResponse response = builder.build(); future.complete(response); @@ -356,9 +328,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - Partition partition = request.getPartition(); - String topicName = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); - int queueId = partition.getId(); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + int queueId = request.getMessageQueue().getId(); long offset; if (request.getPolicy() == QueryOffsetPolicy.BEGINNING) { @@ -372,7 +343,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .getOffsetInQueueByTime(topicName, queueId, timestamp); } return CompletableFuture.completedFuture(QueryOffsetResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, "ok")) + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "ok")) .setOffset(offset) .build()); } @@ -380,7 +351,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); - PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); + PullMessageRequestHeader requestHeader = GrpcConverterV2.buildPullMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -405,92 +376,94 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override - public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - String clientId = request.getClientId(); - CompletableFuture future = new CompletableFuture<>(); - switch (request.getGroupCase()) { - case PRODUCER_GROUP: - Resource producerGroup = request.getProducerGroup(); - String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); - GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); - if (producerChannel == null) { - future.complete(PollCommandResponse.newBuilder() - .setNoopCommand(NoopCommand.newBuilder().build()) - .build()); - break; - } - producerChannel.setClientObserver(future); - break; - case CONSUMER_GROUP: - Resource consumerGroup = request.getConsumerGroup(); - String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); - GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); - if (consumerChannel == null) { - future.complete(PollCommandResponse.newBuilder() - .setNoopCommand(NoopCommand.newBuilder().build()) - .build()); - break; - } - consumerChannel.setClientObserver(future); - break; - default: - break; - } - return future; - } - - @Override - public CompletableFuture reportThreadStackTrace(Context ctx, - ReportThreadStackTraceRequest request) { - String commandId = request.getCommandId(); - String threadStack = request.getThreadStackTrace(); - PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); - if (pollCommandResponseFuture != null) { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); - remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(threadStack); - remotingCommand.setBody(runningInfo.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); - } - } - return CompletableFuture.completedFuture(ReportThreadStackTraceResponse.newBuilder() - .setCommon(ResponseBuilder.buildSuccessCommon()) - .build()); - } - - @Override - public CompletableFuture reportMessageConsumptionResult(Context ctx, - ReportMessageConsumptionResultRequest request) { - - String commandId = request.getCommandId(); - PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); - if (pollCommandResponseFuture != null) { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); - remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); - remotingCommand.setBody(result.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); - } - } - return CompletableFuture.completedFuture(ReportMessageConsumptionResultResponse.newBuilder() - .setCommon(ResponseBuilder.buildSuccessCommon()) - .build()); - } +// @Override +// public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { +// String clientId = request.getClientId(); +// CompletableFuture future = new CompletableFuture<>(); +// switch (request.getGroupCase()) { +// case PRODUCER_GROUP: +// Resource producerGroup = request.getProducerGroup(); +// String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); +// GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); +// if (producerChannel == null) { +// future.complete(PollCommandResponse.newBuilder() +// .setNoopCommand(NoopCommand.newBuilder().build()) +// .build()); +// break; +// } +// producerChannel.setClientObserver(future); +// break; +// case CONSUMER_GROUP: +// Resource consumerGroup = request.getConsumerGroup(); +// String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); +// GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); +// if (consumerChannel == null) { +// future.complete(PollCommandResponse.newBuilder() +// .setNoopCommand(NoopCommand.newBuilder().build()) +// .build()); +// break; +// } +// consumerChannel.setClientObserver(future); +// break; +// default: +// break; +// } +// return future; +// } +// +// @Override +// public CompletableFuture reportThreadStackTrace(Context ctx, +// ReportThreadStackTraceRequest request) { +// String commandId = request.getCommandId(); +// String threadStack = request.getThreadStackTrace(); +// PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); +// if (pollCommandResponseFuture != null) { +// RemotingServer remotingServer = this.brokerController.getRemotingServer(); +// if (remotingServer instanceof NettyRemotingAbstract) { +// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); +// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); +// ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); +// runningInfo.setJstack(threadStack); +// remotingCommand.setBody(runningInfo.encode()); +// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); +// } +// } +// return CompletableFuture.completedFuture(ReportThreadStackTraceResponse.newBuilder() +// .setCommon(ResponseBuilder.buildSuccessCommon()) +// .build()); +// } +// +// @Override +// public CompletableFuture reportMessageConsumptionResult(Context ctx, +// ReportMessageConsumptionResultRequest request) { +// +// String commandId = request.getCommandId(); +// PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); +// if (pollCommandResponseFuture != null) { +// RemotingServer remotingServer = this.brokerController.getRemotingServer(); +// if (remotingServer instanceof NettyRemotingAbstract) { +// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); +// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); +// ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); +// remotingCommand.setBody(result.encode()); +// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); +// } +// } +// return CompletableFuture.completedFuture(ReportMessageConsumptionResultResponse.newBuilder() +// .setCommon(ResponseBuilder.buildSuccessCommon()) +// .build()); +// } @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(request); + String clientId = GrpcClientManager.getClientId(ctx); + ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + UnregisterClientRequestHeader header = GrpcConverterV2.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); remotingCommand.makeCustomHeaderToNet(); @@ -507,7 +480,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request); ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -518,7 +491,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(responseCommand.getCode(), responseCommand.getRemark())); + .setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); if (responseCommand.getCode() == ResponseCode.SUCCESS) { builder.setReceiptHandle(ReceiptHandle.builder() .startOffset(requestHeader.getOffset()) From 62c14bfdb942c1cbae2c8ab94fc01aec61486616 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 6 Apr 2022 16:58:07 +0800 Subject: [PATCH 086/338] [ISSUE #3949] Add telemetry --- .../proxy/grpc/GrpcMessagingProcessorV2.java | 65 ++--- .../proxy/grpc/adapter/GrpcConverterV2.java | 20 +- .../adapter/channel/GrpcClientChannelV2.java | 161 ++++++++++++ .../proxy/grpc/service/GrpcClientManager.java | 21 +- .../grpc/service/GrpcForwardServiceV2.java | 6 +- .../proxy/grpc/service/LocalGrpcService.java | 241 +++++++++++------- 6 files changed, 362 insertions(+), 152 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java index 6a282ff55a..3f5dd2e089 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java @@ -17,34 +17,34 @@ package org.apache.rocketmq.proxy.grpc; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; -import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.QueryOffsetResponse; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.PullMessageResponse; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Status; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; @@ -249,21 +249,6 @@ public class GrpcMessagingProcessorV2 extends MessagingServiceGrpc.MessagingServ @Override public StreamObserver telemetry(StreamObserver responseObserver) { - return new StreamObserver() { - @Override - public void onNext(TelemetryCommand request) { - - } - - @Override - public void onError(Throwable t) { - - } - - @Override - public void onCompleted() { - - } - }; + return grpcForwardService.telemetry(Context.current(), responseObserver); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java index e48f062183..7679fb4d8b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.grpc.adapter; import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; @@ -59,6 +60,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; @@ -267,7 +269,23 @@ public class GrpcConverterV2 { return changeInvisibleTimeRequestHeader; } - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(NackMessageRequest request, int maxReconsumeTimes) { + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); + return changeInvisibleTimeRequestHeader; + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( + NackMessageRequest request, int maxReconsumeTimes) { String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java new file mode 100644 index 0000000000..793df7b679 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java @@ -0,0 +1,161 @@ +/* + * 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.grpc.adapter.channel; + +import apache.rocketmq.v2.PrintThreadStackTraceCommand; +import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import io.netty.channel.ChannelFuture; +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannel; +import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class GrpcClientChannelV2 extends SimpleChannel { + private final AtomicReference> telemetryCommandRef = new AtomicReference<>(); + + private final String group; + private final String clientId; + private final PollResponseManager manager; + + private GrpcClientChannelV2(Context ctx, String group, String clientId, PollResponseManager manager) { + super(ChannelManager.createSimpleChannelDirectly(ctx)); + this.group = group; + this.clientId = clientId; + this.manager = manager; + } + + public void setClientObserver(StreamObserver future) { + this.telemetryCommandRef.set(future); + } + + public static GrpcClientChannelV2 create( + ChannelManager channelManager, + String group, + String clientId, + PollResponseManager manager + ) { + return create(Context.current(), channelManager, group, clientId, manager); + } + + public static GrpcClientChannelV2 create( + Context ctx, + ChannelManager channelManager, + String group, + String clientId, + PollResponseManager manager + ) { + GrpcClientChannelV2 channel = channelManager.createChannel( + buildKey(group, clientId), + () -> new GrpcClientChannelV2(ctx, group, clientId, manager), + GrpcClientChannelV2.class + ); + + channelManager.addGroupClientId(group, clientId); + return channel; + } + + public static GrpcClientChannelV2 getChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannelV2.class); + } + + public static GrpcClientChannelV2 removeChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannelV2.class); + } + + private static String buildKey(String group, String clientId) { + return group + "@" + clientId; + } + + @Override + public boolean isWritable() { + if (this.telemetryCommandRef.get() == null) { + return false; + } + return true; + } + + /** + * Write response to corresponding remote client + * + * @param msg Target write object, {@link RemotingCommand} or {@link TelemetryCommand} + * @return Always success {@link ChannelFuture} + *

+ * Case {@link RequestCode#CHECK_TRANSACTION_STATE} + * @see org.apache.rocketmq.broker.client.net.Broker2Client#checkProducerTransactionState + */ + @Override + public ChannelFuture writeAndFlush(Object msg) { + StreamObserver streamObserver = telemetryCommandRef.get(); + if (msg instanceof RemotingCommand) { + RemotingCommand command = (RemotingCommand) msg; + try { + switch (command.getCode()) { + case RequestCode.CHECK_TRANSACTION_STATE: { + final CheckTransactionStateRequestHeader requestHeader = command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); + streamObserver.onNext(TelemetryCommand.newBuilder() + .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() + .setTransactionId(requestHeader.getTransactionId()) + .setOrphanedTransactionalMessage(GrpcConverterV2.buildMessage(messageExt)) + .build()) + .build()); + break; + } + case RequestCode.GET_CONSUMER_RUNNING_INFO: { + final GetConsumerRunningInfoRequestHeader requestHeader = command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); + if (!requestHeader.isJstackEnable()) { + break; + } + String nonce = manager.putResponse(command.getOpaque()); + streamObserver.onNext(TelemetryCommand.newBuilder() + .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() + .setNonce(nonce) + .build()) + .build()); + break; + } + } + } catch (Exception ignore) { + + } + } + if (msg instanceof TelemetryCommand) { + TelemetryCommand response = (TelemetryCommand) msg; + streamObserver.onNext(response); + } + return super.writeAndFlush(msg); + } + + public String getGroup() { + return group; + } + + public String getClientId() { + return clientId; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java index 3785f6c265..2911a72ae6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java @@ -18,37 +18,24 @@ package org.apache.rocketmq.proxy.grpc.service; import apache.rocketmq.v2.ClientSettings; -import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; -import io.grpc.stub.StreamObserver; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { - private static final Map CLIENT_DATA = new ConcurrentHashMap<>(); + private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); public static ClientSettings getClientSettings(Context ctx) { - return CLIENT_DATA.get(getClientId(ctx)).clientSettings; + return CLIENT_SETTINGS_MAP.get(getClientId(ctx)); } - public static void updateClientData(Context ctx, ClientSettings clientSettings, StreamObserver responseStreamObserver) { - CLIENT_DATA.put(getClientId(ctx), new ClientData(clientSettings, responseStreamObserver)); + public static void updateClientSettings(Context ctx, ClientSettings clientSettings) { + CLIENT_SETTINGS_MAP.put(getClientId(ctx), clientSettings); } public static String getClientId(Context ctx) { return InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); } - - public static class ClientData { - private final ClientSettings clientSettings; - private final StreamObserver responseStreamObserver; - - public ClientData(ClientSettings clientSettings, - StreamObserver responseStreamObserver) { - this.clientSettings = clientSettings; - this.responseStreamObserver = responseStreamObserver; - } - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java index 0e58a68188..ac231b8bdf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java @@ -43,7 +43,9 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; +import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -63,8 +65,6 @@ public interface GrpcForwardServiceV2 extends StartAndShutdown { CompletableFuture ackMessage(Context ctx, AckMessageRequest request); - CompletableFuture nackMessage(Context ctx, NackMessageRequest request); - CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); @@ -76,4 +76,6 @@ public interface GrpcForwardServiceV2 extends StartAndShutdown { CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); + + StreamObserver telemetry(Context ctx, StreamObserver responseObserver); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java index b7c1841313..4a9daf6c75 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java @@ -21,8 +21,10 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.ClientOverwrittenSettings; import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Direction; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -33,6 +35,7 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; @@ -44,10 +47,17 @@ import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.ThreadStackTrace; +import apache.rocketmq.v2.VerifyMessageResult; import com.google.protobuf.util.Timestamps; import io.grpc.Context; +import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -63,6 +73,8 @@ import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; @@ -83,10 +95,11 @@ import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; +import org.apache.rocketmq.proxy.grpc.adapter.PollResponseFuture; import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannelV2; import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; @@ -95,6 +108,8 @@ import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHand import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.remoting.RemotingServer; +import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; @@ -137,24 +152,49 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); HeartbeatData heartbeatData = GrpcConverterV2.buildHeartbeatData(clientId, request, clientSettings); - - CompletableFuture future = new CompletableFuture<>(); - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); command.setVersion(MQVersion.Version.V5_0_0.ordinal()); command.setBody(heartbeatData.encode()); command.makeCustomHeaderToNet(); - RemotingCommand response = this.brokerController.getClientManageProcessor() - .heartBeat(simpleChannelHandlerContext, command); - HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) - .build(); - future.complete(heartbeatResponse); + CompletableFuture future = new CompletableFuture<>(); + switch (clientSettings.getClientType()) { + case PRODUCER: { + for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); + GrpcClientChannelV2 channel = GrpcClientChannelV2.create(channelManager, topicName, clientId, pollCommandResponseManager); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + + this.brokerController.getClientManageProcessor() + .heartBeat(simpleChannelHandlerContext, command); + } + HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "Producer heartbeat")) + .build(); + future.complete(heartbeatResponse); + break; + } + case PULL_CONSUMER: + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: { + String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannelV2 channel = GrpcClientChannelV2.create(channelManager, groupName, clientId, pollCommandResponseManager); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + + RemotingCommand response = this.brokerController.getClientManageProcessor() + .heartBeat(simpleChannelHandlerContext, command); + HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) + .build(); + future.complete(heartbeatResponse); + break; + } + default: { + throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); + } + } + return future; } @@ -376,85 +416,42 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } -// @Override -// public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { -// String clientId = request.getClientId(); -// CompletableFuture future = new CompletableFuture<>(); -// switch (request.getGroupCase()) { -// case PRODUCER_GROUP: -// Resource producerGroup = request.getProducerGroup(); -// String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); -// GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, producerGroupName, clientId); -// if (producerChannel == null) { -// future.complete(PollCommandResponse.newBuilder() -// .setNoopCommand(NoopCommand.newBuilder().build()) -// .build()); -// break; -// } -// producerChannel.setClientObserver(future); -// break; -// case CONSUMER_GROUP: -// Resource consumerGroup = request.getConsumerGroup(); -// String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); -// GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, consumerGroupName, clientId); -// if (consumerChannel == null) { -// future.complete(PollCommandResponse.newBuilder() -// .setNoopCommand(NoopCommand.newBuilder().build()) -// .build()); -// break; -// } -// consumerChannel.setClientObserver(future); -// break; -// default: -// break; -// } -// return future; -// } -// -// @Override -// public CompletableFuture reportThreadStackTrace(Context ctx, -// ReportThreadStackTraceRequest request) { -// String commandId = request.getCommandId(); -// String threadStack = request.getThreadStackTrace(); -// PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); -// if (pollCommandResponseFuture != null) { -// RemotingServer remotingServer = this.brokerController.getRemotingServer(); -// if (remotingServer instanceof NettyRemotingAbstract) { -// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); -// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); -// ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); -// runningInfo.setJstack(threadStack); -// remotingCommand.setBody(runningInfo.encode()); -// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); -// } -// } -// return CompletableFuture.completedFuture(ReportThreadStackTraceResponse.newBuilder() -// .setCommon(ResponseBuilder.buildSuccessCommon()) -// .build()); -// } -// -// @Override -// public CompletableFuture reportMessageConsumptionResult(Context ctx, -// ReportMessageConsumptionResultRequest request) { -// -// String commandId = request.getCommandId(); -// PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(commandId); -// if (pollCommandResponseFuture != null) { -// RemotingServer remotingServer = this.brokerController.getRemotingServer(); -// if (remotingServer instanceof NettyRemotingAbstract) { -// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); -// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); -// ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); -// remotingCommand.setBody(result.encode()); -// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); -// } -// } -// return CompletableFuture.completedFuture(ReportMessageConsumptionResultResponse.newBuilder() -// .setCommon(ResponseBuilder.buildSuccessCommon()) -// .build()); -// } + public void reportThreadStackTrace(ThreadStackTrace request) { + String nonce = request.getNonce(); + String threadStack = request.getThreadStackTrace(); + PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(nonce); + if (pollCommandResponseFuture != null) { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); + remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(threadStack); + remotingCommand.setBody(runningInfo.encode()); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + } + } + } + + public void reportVerifyMessageResult(VerifyMessageResult request) { + String nonce = request.getNonce(); + PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(nonce); + if (pollCommandResponseFuture != null) { + Integer opaque = pollCommandResponseFuture.getOpaque(); + if (opaque != null) { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); + remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); + ConsumeMessageDirectlyResult result = GrpcConverterV2.buildConsumeMessageDirectlyResult(request); + remotingCommand.setBody(result.encode()); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + } + } + } + } @Override public CompletableFuture notifyClientTermination(Context ctx, @@ -514,6 +511,66 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } + @Override + public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(TelemetryCommand request) { + switch (request.getCommandCase()) { + case CLIENT_SETTINGS: { + ClientSettings clientSettings = request.getClientSettings(); + GrpcClientManager.updateClientSettings(ctx, clientSettings); + String clientId = GrpcClientManager.getClientId(ctx); + Settings settings = clientSettings.getSettings(); + if (settings.hasPublishing()) { + Publishing publishing = settings.getPublishing(); + for (Resource topic : publishing.getTopicsList()) { + String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); + GrpcClientChannelV2 producerChannel = GrpcClientChannelV2.getChannel(channelManager, topicName, clientId); + producerChannel.setClientObserver(responseObserver); + } + } + if (settings.hasSubscription()) { + Subscription subscription = settings.getSubscription(); + String groupName = GrpcConverterV2.wrapResourceWithNamespace(subscription.getGroup()); + GrpcClientChannelV2 consumerChannel = GrpcClientChannelV2.getChannel(channelManager, groupName, clientId); + consumerChannel.setClientObserver(responseObserver); + } + responseObserver.onNext(TelemetryCommand.newBuilder() + .setClientOverwrittenSettings(ClientOverwrittenSettings.newBuilder() + .setNonce(clientSettings.getNonce()) + .setDirection(Direction.RESPONSE) + .setSettings(settings) + .build()) + .build()); + break; + } + case THREAD_STACK_TRACE: { + reportThreadStackTrace(request.getThreadStackTrace()); + break; + } + case VERIFY_MESSAGE_RESULT: { + reportVerifyMessageResult(request.getVerifyMessageResult()); + break; + } + default: { + throw new IllegalArgumentException("Request type is illegal"); + } + } + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + }; + } + private class LocalGrpcServiceStartAndShutdown implements StartAndShutdown { @Override public void start() throws Exception { LocalGrpcService.this.scheduledExecutorService.scheduleWithFixedDelay(LocalGrpcService.this::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); From 53fd599d80d602e6e540f8a4d55846b213cea391 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 7 Apr 2022 11:27:07 +0800 Subject: [PATCH 087/338] [ISSUE #3949] Refector package structure --- .../apache/rocketmq/proxy/ProxyStartup.java | 8 +- .../proxy/channel/ChannelManager.java | 2 +- .../proxy/channel/InvocationChannel.java | 3 +- .../InvocationContext.java | 2 +- .../{grpc/adapter => common}/DelayPolicy.java | 2 +- .../ParameterConverter.java | 2 +- .../PollResponseFuture.java | 2 +- .../PollResponseManager.java | 2 +- .../rocketmq/proxy/config/ProxyConfig.java | 2 +- .../rocketmq/proxy/grpc/GrpcServer.java | 3 +- .../proxy/grpc/adapter/ProxyResponseCode.java | 29 ----- .../grpc/adapter/channel/ChannelType.java | 29 ----- .../AuthenticationInterceptor.java | 2 +- .../grpc/{ => v1}/GrpcMessagingProcessor.java | 10 +- .../grpc/{ => v1}/adapter/GrpcConverter.java | 3 +- .../grpc/{ => v1}/adapter/ProxyException.java | 2 +- .../{ => v1}/adapter/ResponseBuilder.java | 2 +- .../adapter/channel/GrpcClientChannel.java | 6 +- .../{ => v1}/service/ClusterGrpcService.java | 20 ++-- .../{ => v1}/service/GrpcForwardService.java | 2 +- .../GrpcMessagingProcessor.java} | 24 ++-- .../adapter/GrpcConverter.java} | 56 +++++----- .../adapter/ProxyException.java} | 8 +- .../grpc/{ => v2}/adapter/ProxyMode.java | 2 +- .../v2/adapter}/RequestMapping.java | 2 +- .../adapter/ResponseBuilder.java} | 4 +- .../grpc/{ => v2}/adapter/ResponseHook.java | 2 +- .../grpc/{ => v2}/adapter/ResponseWriter.java | 2 +- .../adapter/channel/GrpcClientChannel.java} | 30 ++--- .../adapter/channel/PullMessageChannel.java | 4 +- .../channel/ReceiveMessageChannel.java | 4 +- .../adapter/channel/SendMessageChannel.java | 4 +- .../handler/PullMessageResponseHandler.java | 12 +- .../ReceiveMessageResponseHandler.java | 14 +-- .../adapter/handler/ResponseHandler.java | 4 +- .../handler/SendMessageResponseHandler.java | 8 +- .../service/ClusterGrpcService.java} | 33 +++--- .../{ => v2}/service/GrpcClientManager.java | 2 +- .../service/GrpcForwardService.java} | 4 +- .../{ => v2}/service/LocalGrpcService.java | 103 +++++++++--------- .../cluster/AssignmentQueueSelector.java | 2 +- .../{ => v2}/service/cluster/BaseService.java | 16 +-- .../service/cluster/ConsumerService.java | 48 ++++---- .../DefaultAssignmentQueueSelector.java | 6 +- .../cluster/DefaultReadQueueSelector.java | 2 +- .../cluster/DefaultWriteQueueSelector.java | 2 +- .../service/cluster/ForwardClientService.java | 8 +- .../service/cluster/ProducerService.java | 26 ++--- .../service/cluster/PullMessageService.java | 22 ++-- .../service/cluster/ReadQueueSelector.java | 2 +- .../service/cluster/RouteService.java | 26 ++--- .../service/cluster/TransactionService.java | 18 +-- .../service/cluster/WriteQueueSelector.java | 2 +- .../config/ConfigurationManagerTest.java | 2 +- .../service/LocalGrpcServiceTest.java | 70 ++++++------ .../service/cluster/BaseServiceTest.java | 2 +- .../service/cluster/ConsumerServiceTest.java | 2 +- .../cluster/DefaultReadQueueSelectorTest.java | 2 +- .../DefaultWriteQueueSelectorTest.java | 4 +- .../cluster/ForwardClientServiceTest.java | 6 +- .../service/cluster/ProducerServiceTest.java | 4 +- .../cluster/PullMessageServiceTest.java | 2 +- .../service/cluster/RouteServiceTest.java | 4 +- .../cluster/TransactionServiceTest.java | 4 +- .../rocketmq/test/proxy/ClusterGrpcTest.java | 6 +- .../rocketmq/test/proxy/LocalGrpcTest.java | 4 +- 66 files changed, 342 insertions(+), 405 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => channel}/InvocationContext.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => common}/DelayPolicy.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => common}/ParameterConverter.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => common}/PollResponseFuture.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/adapter => common}/PollResponseManager.java (96%) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/GrpcMessagingProcessor.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/adapter/GrpcConverter.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/adapter/ProxyException.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/adapter/ResponseBuilder.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/adapter/channel/GrpcClientChannel.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/service/ClusterGrpcService.java (93%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v1}/service/GrpcForwardService.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{GrpcMessagingProcessorV2.java => v2/GrpcMessagingProcessor.java} (92%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{adapter/GrpcConverterV2.java => v2/adapter/GrpcConverter.java} (92%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{adapter/ProxyExceptionV2.java => v2/adapter/ProxyException.java} (81%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/ProxyMode.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{common => grpc/v2/adapter}/RequestMapping.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{adapter/ResponseBuilderV2.java => v2/adapter/ResponseBuilder.java} (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/ResponseHook.java (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/ResponseWriter.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{adapter/channel/GrpcClientChannelV2.java => v2/adapter/channel/GrpcClientChannel.java} (85%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/channel/PullMessageChannel.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/channel/ReceiveMessageChannel.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/channel/SendMessageChannel.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/handler/PullMessageResponseHandler.java (85%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/handler/ReceiveMessageResponseHandler.java (93%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/handler/ResponseHandler.java (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/adapter/handler/SendMessageResponseHandler.java (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{service/ClusterGrpcServiceV2.java => v2/service/ClusterGrpcService.java} (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/GrpcClientManager.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{service/GrpcForwardServiceV2.java => v2/service/GrpcForwardService.java} (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/LocalGrpcService.java (86%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/AssignmentQueueSelector.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/BaseService.java (77%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ConsumerService.java (87%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/DefaultAssignmentQueueSelector.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/DefaultReadQueueSelector.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/DefaultWriteQueueSelector.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ForwardClientService.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ProducerService.java (87%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/PullMessageService.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ReadQueueSelector.java (95%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/RouteService.java (93%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/TransactionService.java (89%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/WriteQueueSelector.java (95%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/LocalGrpcServiceTest.java (93%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/BaseServiceTest.java (98%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ConsumerServiceTest.java (99%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/DefaultReadQueueSelectorTest.java (98%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/DefaultWriteQueueSelectorTest.java (98%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ForwardClientServiceTest.java (96%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/ProducerServiceTest.java (98%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/PullMessageServiceTest.java (98%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/RouteServiceTest.java (99%) rename proxy/src/test/java/org/apache/rocketmq/proxy/grpc/{ => v2}/service/cluster/TransactionServiceTest.java (96%) 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 7d2640293f..accb214777 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -30,10 +30,10 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; -import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 6c6349bdd1..5adc5e0b80 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -31,7 +31,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.common.Cleaner; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java index 80750f5fb2..4e04086797 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -24,8 +24,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.rocketmq.proxy.common.Cleaner; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.handler.ResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ResponseHandler; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public abstract class InvocationChannel extends SimpleChannel implements Cleaner { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationContext.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationContext.java index 1260b0b04b..99b6d1f1b1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/InvocationContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationContext.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.channel; import java.time.Duration; import java.util.concurrent.CompletableFuture; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java index 722910ae18..b0220e14e1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/DelayPolicy.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.common; import com.google.common.base.Splitter; import com.google.common.collect.Lists; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java index 47641cf700..2632d4340f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ParameterConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.common; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java index 0bd79de2b6..fdf68b2117 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseFuture.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.common; public class PollResponseFuture { private final String commandId; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java index 8379fdf4c8..a6dfd335e3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/PollResponseManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.common; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; 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 9c09b8bb33..37b4281430 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 @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; 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 8be76a95d3..9b22e8d07b 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 @@ -39,7 +39,8 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; -import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java deleted file mode 100644 index 0c1fa6ee00..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyResponseCode.java +++ /dev/null @@ -1,29 +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.proxy.grpc.adapter; - -public enum ProxyResponseCode { - SYS_ERR, - PARAMETER_ERR, - AUTH_PERMISSION_CHECK_ERROR, - - NO_TOPIC_ROUTE, - SUBSCRIPTION_NOT_CONSISTENT, - BROKER_NOT_EXIST, - QUERY_NOT_FOUND, - SEND_MSG_FAILED; -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java deleted file mode 100644 index da8d30de8d..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ChannelType.java +++ /dev/null @@ -1,29 +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.proxy.grpc.adapter.channel; - -public enum ChannelType { - /** - * The channel connect to current proxy directly - */ - LOCAL, - /** - * The channel synced from other proxy - */ - REMOTE -} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index c93b829f55..e79453f9b7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -27,7 +27,7 @@ import io.grpc.ServerInterceptor; import java.util.List; import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.MetadataHeader; -import org.apache.rocketmq.proxy.common.RequestMapping; +import org.apache.rocketmq.proxy.grpc.v2.adapter.RequestMapping; public class AuthenticationInterceptor implements ServerInterceptor { private final List accessValidatorList; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java index fe8a4f6aac..bfafbdb777 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc; +package org.apache.rocketmq.proxy.grpc.v1; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; @@ -59,10 +59,10 @@ import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v1.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java index 46c8d3d6ae..7be0496eef 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v1.adapter; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.ChangeInvisibleDurationRequest; @@ -89,6 +89,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java index da19dafc4e..f452d88c28 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v1.adapter; import com.google.rpc.Code; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java index d475d11fa1..aa27f420e6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v1.adapter; import apache.rocketmq.v1.HeartbeatResponse; import apache.rocketmq.v1.ResponseCommon; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java index bcdc46173f..5f993ff2b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.grpc.v1.adapter.channel; import apache.rocketmq.v1.PollCommandResponse; import apache.rocketmq.v1.PrintThreadStackTraceCommand; @@ -31,8 +31,8 @@ import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.common.PollResponseManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java similarity index 93% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java index ce94063d69..94b1e56798 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v1.service; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; @@ -64,15 +64,15 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.service.cluster.ForwardClientService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ConsumerService; -import org.apache.rocketmq.proxy.grpc.service.cluster.ProducerService; -import org.apache.rocketmq.proxy.grpc.service.cluster.PullMessageService; -import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; -import org.apache.rocketmq.proxy.grpc.service.cluster.TransactionService; +import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.PullMessageService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java index a8efceb2f1..d279efba95 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v1.service; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java similarity index 92% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index 3f5dd2e089..87cc060e09 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcMessagingProcessorV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc; +package org.apache.rocketmq.proxy.grpc.v2; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; @@ -51,27 +51,27 @@ import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.service.GrpcForwardServiceV2; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; -public class GrpcMessagingProcessorV2 extends MessagingServiceGrpc.MessagingServiceImplBase { +public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { - private final GrpcForwardServiceV2 grpcForwardService; + private final GrpcForwardService grpcForwardService; - public GrpcMessagingProcessorV2(GrpcForwardServiceV2 grpcForwardService) { + public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { this.grpcForwardService = grpcForwardService; } public Status convertExceptionToStatus(Throwable t) { if (t instanceof CompletionException) { - if (t.getCause() instanceof ProxyExceptionV2) { - ProxyExceptionV2 proxyException = (ProxyExceptionV2) t.getCause(); - return ResponseBuilderV2.buildStatus(proxyException.getCode(), proxyException.getMessage()); + if (t.getCause() instanceof ProxyException) { + ProxyException proxyException = (ProxyException) t.getCause(); + return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); } } - return ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); + return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java similarity index 92% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 7679fb4d8b..d7286c57b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/GrpcConverterV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; @@ -60,7 +60,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; @@ -89,13 +88,14 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class GrpcConverterV2 { +public class GrpcConverter { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); public static String wrapResourceWithNamespace(Resource resource) { @@ -168,7 +168,7 @@ public class GrpcConverterV2 { MessageQueue messageQueue = request.getMessageQueue(); if (request.getMessagesCount() <= 0) { - throw new ProxyExceptionV2(Code.MESSAGE_CORRUPTED, "no message to send"); + throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } if (request.getMessagesCount() > 1) { requestHeader.setBatch(true); @@ -204,10 +204,10 @@ public class GrpcConverterV2 { public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { Resource group = request.getGroup(); - String groupName = GrpcConverterV2.wrapResourceWithNamespace(group); + String groupName = GrpcConverter.wrapResourceWithNamespace(group); MessageQueue messageQueue = request.getMessageQueue(); Resource topic = messageQueue.getTopic(); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); int queueId = messageQueue.getId(); int maxMessageNumbers = request.getBatchSize(); if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { @@ -220,7 +220,7 @@ public class GrpcConverterV2 { FilterExpression filterExpression = request.getFilterExpression(); String expression = filterExpression.getExpression(); - String expressionType = GrpcConverterV2.buildExpressionType(filterExpression.getType()); + String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); requestHeader.setConsumerGroup(groupName); @@ -239,8 +239,8 @@ public class GrpcConverterV2 { } public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); @@ -254,8 +254,8 @@ public class GrpcConverterV2 { public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, DelayPolicy delayPolicy) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); @@ -270,8 +270,8 @@ public class GrpcConverterV2 { } public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); @@ -286,8 +286,8 @@ public class GrpcConverterV2 { public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( NackMessageRequest request, int maxReconsumeTimes) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); @@ -302,8 +302,8 @@ public class GrpcConverterV2 { public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( ForwardMessageToDeadLetterQueueRequest request) { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); @@ -324,12 +324,12 @@ public class GrpcConverterV2 { try { handle = TransactionId.decode(transactionId); } catch (Exception e) { - throw new ProxyExceptionV2(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); + throw new ProxyException(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); } long transactionStateTableOffset = handle.getTranStateTableOffset(); long commitLogOffset = handle.getCommitLogOffset(); boolean fromTransactionCheck = request.getSource() == TransactionSource.SOURCE_SERVER_CHECK; - int commitOrRollback = GrpcConverterV2.buildTransactionCommitOrRollback(request.getResolution()); + int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); endTransactionRequestHeader.setProducerGroup(producerGroup); @@ -346,13 +346,13 @@ public class GrpcConverterV2 { public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { MessageQueue messageQueue = request.getMessageQueue(); - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(messageQueue.getTopic()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(messageQueue.getTopic()); int queueId = messageQueue.getId(); int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); String expression = request.getFilterExpression().getExpression(); - String expressionType = GrpcConverterV2.buildExpressionType(request.getFilterExpression().getType()); + String expressionType = GrpcConverter.buildExpressionType(request.getFilterExpression().getType()); PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); requestHeader.setConsumerGroup(groupName); @@ -372,7 +372,7 @@ public class GrpcConverterV2 { public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, ClientType clientType, NotifyClientTerminationRequest request) { UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); header.setClientID(clientId); switch (clientType) { case PRODUCER: { @@ -395,7 +395,7 @@ public class GrpcConverterV2 { Map userProperties = message.getUserPropertiesMap(); for (String key : userProperties.keySet()) { if (MessageConst.STRING_HASH_SET.contains(key)) { - throw new ProxyExceptionV2(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); + throw new ProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); } } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); @@ -415,7 +415,7 @@ public class GrpcConverterV2 { // set message id String messageId = message.getSystemProperties().getMessageId(); if ("".equals(messageId)) { - throw new ProxyExceptionV2(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); + throw new ProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); } MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); @@ -488,7 +488,7 @@ public class GrpcConverterV2 { public static Set buildSubscriptionDataSet(List subscriptionEntryList) { Set subscriptionDataSet = new HashSet<>(); for (SubscriptionEntry sub : subscriptionEntryList) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(sub.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); FilterExpression filterExpression = sub.getExpression(); subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); } @@ -497,11 +497,11 @@ public class GrpcConverterV2 { public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { String expression = filterExpression.getExpression(); - String expressionType = GrpcConverterV2.buildExpressionType(filterExpression.getType()); + String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); try { return FilterAPI.build(topicName, expression, expressionType); } catch (Exception e) { - throw new ProxyExceptionV2(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); + throw new ProxyException(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyException.java similarity index 81% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyException.java index 12ead80221..b6de2f47f5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyExceptionV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyException.java @@ -14,20 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.Code; -public class ProxyExceptionV2 extends RuntimeException { +public class ProxyException extends RuntimeException { private final Code code; - public ProxyExceptionV2(Code code, String errorMessage) { + public ProxyException(Code code, String errorMessage) { super(errorMessage); this.code = code; } - public ProxyExceptionV2(Code code, String message, Throwable cause) { + public ProxyException(Code code, String message, Throwable cause) { super(message, cause); this.code = code; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyMode.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyMode.java index 73856c64b5..631bcaadca 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ProxyMode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyMode.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; public enum ProxyMode { LOCAL("LOCAL"), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index 7a2ae4dd22..fe00bd12a4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.common; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.ChangeInvisibleDurationRequest; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index dc99e0e75d..487a526007 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseBuilderV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -15,13 +15,13 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Status; import org.apache.rocketmq.common.protocol.ResponseCode; -public class ResponseBuilderV2 { +public class ResponseBuilder { public static Status buildStatus(Code code, String message) { return Status.newBuilder() .setCode(code) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java index f18f6dc19d..45fe954bda 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseHook.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 88d123758e..653d9d7e10 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter; +package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java similarity index 85% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 793df7b679..8a945ef7da 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/GrpcClientChannelV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.PrintThreadStackTraceCommand; import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; @@ -31,18 +31,18 @@ import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.common.PollResponseManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class GrpcClientChannelV2 extends SimpleChannel { +public class GrpcClientChannel extends SimpleChannel { private final AtomicReference> telemetryCommandRef = new AtomicReference<>(); private final String group; private final String clientId; private final PollResponseManager manager; - private GrpcClientChannelV2(Context ctx, String group, String clientId, PollResponseManager manager) { + private GrpcClientChannel(Context ctx, String group, String clientId, PollResponseManager manager) { super(ChannelManager.createSimpleChannelDirectly(ctx)); this.group = group; this.clientId = clientId; @@ -53,7 +53,7 @@ public class GrpcClientChannelV2 extends SimpleChannel { this.telemetryCommandRef.set(future); } - public static GrpcClientChannelV2 create( + public static GrpcClientChannel create( ChannelManager channelManager, String group, String clientId, @@ -62,29 +62,29 @@ public class GrpcClientChannelV2 extends SimpleChannel { return create(Context.current(), channelManager, group, clientId, manager); } - public static GrpcClientChannelV2 create( + public static GrpcClientChannel create( Context ctx, ChannelManager channelManager, String group, String clientId, PollResponseManager manager ) { - GrpcClientChannelV2 channel = channelManager.createChannel( + GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), - () -> new GrpcClientChannelV2(ctx, group, clientId, manager), - GrpcClientChannelV2.class + () -> new GrpcClientChannel(ctx, group, clientId, manager), + GrpcClientChannel.class ); channelManager.addGroupClientId(group, clientId); return channel; } - public static GrpcClientChannelV2 getChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannelV2.class); + public static GrpcClientChannel getChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannel.class); } - public static GrpcClientChannelV2 removeChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannelV2.class); + public static GrpcClientChannel removeChannel(ChannelManager channelManager, String group, String clientId) { + return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannel.class); } private static String buildKey(String group, String clientId) { @@ -121,7 +121,7 @@ public class GrpcClientChannelV2 extends SimpleChannel { streamObserver.onNext(TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(requestHeader.getTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverterV2.buildMessage(messageExt)) + .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) .build()) .build()); break; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java index ae3fa27daf..d65c74aba9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/PullMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.PullMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.PullMessageResponseHandler; public class PullMessageChannel extends InvocationChannel { public PullMessageChannel(PullMessageResponseHandler handler) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java index 860502391b..a561c1e444 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; public class ReceiveMessageChannel extends InvocationChannel { public ReceiveMessageChannel(ReceiveMessageResponseHandler handler) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java index d8cc965a0c..39ce672299 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java @@ -15,12 +15,12 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.channel; +package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; public class SendMessageChannel extends InvocationChannel { public SendMessageChannel(SendMessageResponseHandler handler) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java similarity index 85% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java index 18495e295f..d4e351121a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/PullMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.handler; +package org.apache.rocketmq.proxy.grpc.v2.adapter.handler; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.PullMessageResponse; @@ -25,9 +25,9 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class PullMessageResponseHandler implements ResponseHandler { @@ -41,10 +41,10 @@ public class PullMessageResponseHandler implements ResponseHandler msgFoundList = MessageDecoder.decodes(byteBuffer); for (MessageExt messageExt : msgFoundList) { - builder.addMessages(GrpcConverterV2.buildMessage(messageExt)); + builder.addMessages(GrpcConverter.buildMessage(messageExt)); } } - PullMessageResponse response = builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + PullMessageResponse response = builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) .setMinOffset(responseHeader.getMinOffset()) .setNextOffset(responseHeader.getNextBeginOffset()) .setMaxOffset(responseHeader.getMaxOffset()) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java similarity index 93% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 6b5cf9bc46..88066c25d1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.handler; +package org.apache.rocketmq.proxy.grpc.v2.adapter.handler; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; @@ -36,9 +36,9 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; import org.slf4j.Logger; @@ -65,7 +65,7 @@ public class ReceiveMessageResponseHandler implements ResponseHandler { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java index 39fdd6f2b2..0716c404f5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/adapter/handler/SendMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.adapter.handler; +package org.apache.rocketmq.proxy.grpc.v2.adapter.handler; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SendReceipt; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; +import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class SendMessageResponseHandler implements ResponseHandler { @@ -44,7 +44,7 @@ public class SendMessageResponseHandler implements ResponseHandler telemetry(Context ctx, TelemetryCommand request) { - return null; - } - @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { @@ -171,6 +167,11 @@ public class ClusterGrpcServiceV2 extends AbstractStartAndShutdown implements Gr return null; } + @Override + public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + return null; + } + private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index 2911a72ae6..8371d2eaee 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.ClientSettings; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java index ac231b8bdf..eb11cf4ade 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/GrpcForwardServiceV2.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; @@ -49,7 +49,7 @@ import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; -public interface GrpcForwardServiceV2 extends StartAndShutdown { +public interface GrpcForwardService extends StartAndShutdown { CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 4a9daf6c75..48f3169e30 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; @@ -91,23 +91,22 @@ import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.InvocationContext; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseFuture; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannelV2; -import org.apache.rocketmq.proxy.grpc.adapter.channel.PullMessageChannel; -import org.apache.rocketmq.proxy.grpc.adapter.channel.ReceiveMessageChannel; -import org.apache.rocketmq.proxy.grpc.adapter.channel.SendMessageChannel; -import org.apache.rocketmq.proxy.grpc.adapter.handler.PullMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.adapter.handler.ReceiveMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.adapter.handler.SendMessageResponseHandler; +import org.apache.rocketmq.proxy.common.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.common.PollResponseFuture; +import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.PullMessageChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.PullMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; +import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; @@ -115,7 +114,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardServiceV2 { +public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final BrokerController brokerController; @@ -151,7 +150,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo String clientId = GrpcClientManager.getClientId(ctx); ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); - HeartbeatData heartbeatData = GrpcConverterV2.buildHeartbeatData(clientId, request, clientSettings); + HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); command.setVersion(MQVersion.Version.V5_0_0.ordinal()); @@ -162,15 +161,15 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); - GrpcClientChannelV2 channel = GrpcClientChannelV2.create(channelManager, topicName, clientId, pollCommandResponseManager); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); this.brokerController.getClientManageProcessor() .heartBeat(simpleChannelHandlerContext, command); } HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "Producer heartbeat")) + .setStatus(ResponseBuilder.buildStatus(Code.OK, "Producer heartbeat")) .build(); future.complete(heartbeatResponse); break; @@ -178,14 +177,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { - String groupName = GrpcConverterV2.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannelV2 channel = GrpcClientChannelV2.create(channelManager, groupName, clientId, pollCommandResponseManager); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand response = this.brokerController.getClientManageProcessor() .heartBeat(simpleChannelHandlerContext, command); HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) + .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) .build(); future.complete(heartbeatResponse); break; @@ -200,10 +199,10 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - SendMessageRequestHeader requestHeader = GrpcConverterV2.buildSendMessageRequestHeader(request, topicName); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); - List messageList = GrpcConverterV2.buildMessage(request.getMessagesList(), topicName); + List messageList = GrpcConverter.buildMessage(request.getMessagesList(), topicName); MessageBatch messageBatch = MessageBatch.generateFromList(messageList); MessageClientIDSetter.setUniqID(messageBatch); messageBatch.setBody(messageBatch.encode()); @@ -239,9 +238,9 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - long pollTime = GrpcConverterV2.buildPollTimeFromContext(ctx); + long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); - PopMessageRequestHeader requestHeader = GrpcConverterV2.buildPopMessageRequestHeader(request, pollTime); + PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -270,7 +269,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - AckMessageRequestHeader requestHeader = GrpcConverterV2.buildAckMessageRequestHeader(request); + AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -279,7 +278,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand responseCommand = brokerController.getAckMessageProcessor() .processRequest(channelHandlerContext, command); AckMessageResponse.Builder builder = AckMessageResponse.newBuilder(); - builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); + builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); AckMessageResponse response = builder.build(); future.complete(response); } catch (Exception e) { @@ -293,7 +292,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -302,7 +301,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() .processRequest(channelHandlerContext, command); NackMessageResponse response = NackMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) .build(); future.complete(response); } catch (Exception e) { @@ -318,7 +317,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverterV2.buildConsumerSendMsgBackRequestHeader(request); + ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); command.makeCustomHeaderToNet(); @@ -328,7 +327,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(response.getCode(), response.getRemark())) + .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) .build()); } catch (Exception e) { log.error("Exception raised when forwardMessageToDeadLetterQueue", e); @@ -342,8 +341,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); - EndTransactionRequestHeader requestHeader = GrpcConverterV2.buildEndTransactionRequestHeader(request, topicName); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request, topicName); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); command.makeCustomHeaderToNet(); @@ -353,9 +352,9 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); if (null != responseCommand) { - builder.setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); + builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); } else { - builder.setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); + builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); } EndTransactionResponse response = builder.build(); future.complete(response); @@ -368,7 +367,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); int queueId = request.getMessageQueue().getId(); long offset; @@ -383,15 +382,15 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .getOffsetInQueueByTime(topicName, queueId, timestamp); } return CompletableFuture.completedFuture(QueryOffsetResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "ok")) + .setStatus(ResponseBuilder.buildStatus(Code.OK, "ok")) .setOffset(offset) .build()); } @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); - PullMessageRequestHeader requestHeader = GrpcConverterV2.buildPullMessageRequestHeader(request, pollTime); + long pollTime = org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter.buildPollTimeFromContext(ctx); + PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -445,7 +444,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumeMessageDirectlyResult result = GrpcConverterV2.buildConsumeMessageDirectlyResult(request); + ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); remotingCommand.setBody(result.encode()); nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); } @@ -460,7 +459,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); String clientId = GrpcClientManager.getClientId(ctx); ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); - UnregisterClientRequestHeader header = GrpcConverterV2.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); + UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); remotingCommand.makeCustomHeaderToNet(); @@ -477,7 +476,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); @@ -488,7 +487,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo .processRequest(channelHandlerContext, command); ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); if (responseCommand.getCode() == ResponseCode.SUCCESS) { builder.setReceiptHandle(ReceiptHandle.builder() .startOffset(requestHeader.getOffset()) @@ -525,15 +524,15 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo if (settings.hasPublishing()) { Publishing publishing = settings.getPublishing(); for (Resource topic : publishing.getTopicsList()) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); - GrpcClientChannelV2 producerChannel = GrpcClientChannelV2.getChannel(channelManager, topicName, clientId); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, topicName, clientId); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { Subscription subscription = settings.getSubscription(); - String groupName = GrpcConverterV2.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannelV2 consumerChannel = GrpcClientChannelV2.getChannel(channelManager, groupName, clientId); + String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); + GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, groupName, clientId); consumerChannel.setClientObserver(responseObserver); } responseObserver.onNext(TelemetryCommand.newBuilder() diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java index b92a261304..5151225904 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/AssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.QueryAssignmentRequest; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java similarity index 77% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java index 3be08632a0..758c1ba9db 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; @@ -23,8 +23,8 @@ import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; public class BaseService { @@ -37,25 +37,25 @@ public class BaseService { protected ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); if (receiptHandle.isExpired()) { - throw new ProxyExceptionV2(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); + throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); } return receiptHandle; } protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { if (StringUtils.isBlank(brokerName)) { - throw new ProxyExceptionV2(Code.INVALID_ARGUMENT, "broker name is empty"); + throw new ProxyException(Code.INVALID_ARGUMENT, "broker name is empty"); } String addr = this.connectorManager.getTopicRouteCache().getBrokerAddr(brokerName); if (StringUtils.isBlank(addr)) { - throw new ProxyExceptionV2(Code.NOT_FOUND, brokerName + " not exist"); + throw new ProxyException(Code.NOT_FOUND, brokerName + " not exist"); } return addr; } protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { // for checking filterExpression. - String topicName = GrpcConverterV2.wrapResourceWithNamespace(topic); - GrpcConverterV2.buildSubscriptionData(topicName, filterExpression); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcConverter.buildSubscriptionData(topicName, filterExpression); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java similarity index 87% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index a2f7b34e8e..322e670350 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; @@ -47,12 +47,12 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.service.GrpcClientManager; +import org.apache.rocketmq.proxy.common.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { @@ -94,7 +94,7 @@ public class ConsumerService extends BaseService { SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); if (messageQueue == null) { - throw new ProxyExceptionV2(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); + throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); } CompletableFuture popResultFuture = this.readConsumer.popMessage( @@ -122,7 +122,7 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - return GrpcConverterV2.buildPopMessageRequestHeader(request, GrpcConverterV2.buildPollTimeFromContext(ctx)); + return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { @@ -130,25 +130,25 @@ public class ConsumerService extends BaseService { switch (status) { case FOUND: return ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .addAllMessages(checkAndGetMessagesFromPopResult(ctx, request, result)) .build(); case POLLING_FULL: return ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) .build(); case NO_NEW_MSG: case POLLING_NOT_FOUND: default: return ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, "no new message")) + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) .build(); } } protected List checkAndGetMessagesFromPopResult(Context ctx, ReceiveMessageRequest request, PopResult result) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - SubscriptionData subscriptionData = GrpcConverterV2.buildSubscriptionData(topicName, request.getFilterExpression()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); List messages = new ArrayList<>(); for (MessageExt messageExt : result.getMsgFoundList()) { @@ -156,7 +156,7 @@ public class ConsumerService extends BaseService { this.ackNoMatchedMessage(ctx, request, messageExt); continue; } - messages.add(GrpcConverterV2.buildMessage(messageExt)); + messages.add(GrpcConverter.buildMessage(messageExt)); } return messages; @@ -172,7 +172,7 @@ public class ConsumerService extends BaseService { return; } String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); - ackMessageRequestHeader.setConsumerGroup(GrpcConverterV2.wrapResourceWithNamespace(request.getGroup())); + ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); ackMessageRequestHeader.setTopic(messageExt.getTopic()); ackMessageRequestHeader.setQueueId(handle.getQueueId()); ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); @@ -224,17 +224,17 @@ public class ConsumerService extends BaseService { } protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request) { - return GrpcConverterV2.buildAckMessageRequestHeader(request); + return GrpcConverter.buildAckMessageRequestHeader(request); } protected AckMessageResponse convertToAckMessageResponse(Context ctx, AckMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return AckMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build(); } return AckMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) .build(); } @@ -292,28 +292,28 @@ public class ConsumerService extends BaseService { } protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverterV2.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); + return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request, int maxReconsumeTimes) { - return GrpcConverterV2.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); + return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build(); } return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "nack failed: status is abnormal")) + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "nack failed: status is abnormal")) .build(); } protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, RemotingCommand sendMsgBackToDLQResult) { return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) + .setStatus(ResponseBuilder.buildStatus(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java index 80709fb96a..a27ed2a74f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultAssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.QueryAssignmentRequest; import io.grpc.Context; @@ -22,7 +22,7 @@ import java.util.List; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @@ -34,7 +34,7 @@ public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { @Override public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topicName); return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java index 2acb517abf..97b878b871 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java index 0148038266..f5630848f7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 52f79f6e8c..6df2e87db6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.ConsumerData; import apache.rocketmq.v1.HeartbeatRequest; @@ -36,9 +36,9 @@ import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java similarity index 87% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 30874ed9f3..1c16dea04f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -36,10 +36,10 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyExceptionV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerService extends BaseService { @@ -85,7 +85,7 @@ public class ProducerService extends BaseService { String topic = requestHeader.getTopic(); if (selectableMessageQueue == null) { - throw new ProxyExceptionV2(Code.FORBIDDEN, "no writeable topic route for topic: " + topic); + throw new ProxyException(Code.FORBIDDEN, "no writeable topic route for topic: " + topic); } // send message to broker. @@ -116,17 +116,17 @@ public class ProducerService extends BaseService { protected Pair> buildSendMessageRequest( Context ctx, SendMessageRequest request) { - String topic = GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); // use topic name as group - SendMessageRequestHeader requestHeader = GrpcConverterV2.buildSendMessageRequestHeader(request, topic); - List message = GrpcConverterV2.buildMessage(request.getMessagesList(), topic); + SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topic); + List message = GrpcConverter.buildMessage(request.getMessagesList(), topic); return Pair.of(requestHeader, message); } protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult result) { if (result.getSendStatus() != SendStatus.SEND_OK) { return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) .build(); } @@ -136,7 +136,7 @@ public class ProducerService extends BaseService { .setTransactionId(StringUtils.defaultString(result.getTransactionId())) .build()); return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .addAllReceipts(sendReceiptList) .build(); } @@ -159,7 +159,7 @@ public class ProducerService extends BaseService { .thenAccept(result -> future.complete( ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(result.getCode(), result.getRemark())) + .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) .build() ) ) @@ -175,6 +175,6 @@ public class ProducerService extends BaseService { protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - return GrpcConverterV2.buildConsumerSendMsgBackRequestHeader(request); + return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java index 48ec46ab9b..1a07415e95 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; @@ -36,9 +36,9 @@ import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; public class PullMessageService extends BaseService { private final DefaultForwardClient forwardClient; @@ -63,7 +63,7 @@ public class PullMessageService extends BaseService { try { MessageQueue partition = request.getMessageQueue(); - String topic = GrpcConverterV2.wrapResourceWithNamespace(partition.getTopic()); + String topic = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); String brokerName = partition.getBroker().getName(); int queueId = partition.getId(); @@ -83,7 +83,7 @@ public class PullMessageService extends BaseService { offsetFuture .thenAccept(result -> future.complete( QueryOffsetResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .setOffset(result) .build())) .exceptionally(throwable -> { @@ -132,24 +132,24 @@ public class PullMessageService extends BaseService { protected PullMessageRequestHeader buildPullMessageRequestHeader(Context ctx, PullMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - return GrpcConverterV2.buildPullMessageRequestHeader(request, GrpcConverterV2.buildPollTimeFromContext(ctx)); + return GrpcConverter.buildPullMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); } protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { PullMessageResponse.Builder responseBuilder = PullMessageResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .setMinOffset(result.getMinOffset()) .setMaxOffset(result.getMaxOffset()) .setNextOffset(result.getNextBeginOffset()); - SubscriptionData subscriptionData = GrpcConverterV2.buildSubscriptionData( - GrpcConverterV2.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), request.getFilterExpression()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( + GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), request.getFilterExpression()); PullStatus status = result.getPullStatus(); if (status.equals(PullStatus.FOUND)) { List messageList = result.getMsgFoundList().stream() .filter(msg -> FilterUtils.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. - .map(GrpcConverterV2::buildMessage) + .map(GrpcConverter::buildMessage) .collect(Collectors.toList()); return responseBuilder.addAllMessages(messageList).build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java index 4fa9c6e350..3eb936437a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/ReadQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java similarity index 93% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index d639a149e7..8da26d154e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; @@ -46,11 +46,11 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ParameterConverter; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.common.ParameterConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; public class RouteService extends BaseService { private final ProxyMode mode; @@ -100,7 +100,7 @@ public class RouteService extends BaseService { }); try { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); @@ -111,7 +111,7 @@ public class RouteService extends BaseService { Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + + .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); return future; @@ -142,14 +142,14 @@ public class RouteService extends BaseService { } QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .addAllMessageQueues(messageQueueList) .build(); future.complete(response); } catch (Throwable t) { if (TopicRouteHelper.isTopicNotExistError(t)) { future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) + .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) .build()); } else { future.completeExceptionally(t); @@ -215,7 +215,7 @@ public class RouteService extends BaseService { List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); if (ProxyMode.isLocalMode(mode)) { - String topicName = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); @@ -241,7 +241,7 @@ public class RouteService extends BaseService { Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + + .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + request.getEndpoints() + " is invalidate")) .build()); return future; @@ -268,7 +268,7 @@ public class RouteService extends BaseService { QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() .addAllAssignments(assignments) - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build(); future.complete(response); } catch (Throwable t) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index 8c9814f6b9..4ea9ccd179 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; @@ -34,10 +34,10 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverterV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseBuilderV2; -import org.apache.rocketmq.proxy.grpc.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { @@ -67,7 +67,7 @@ public class TransactionService extends BaseService implements TransactionStateC GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); String transactionId = checkData.getTransactionId().getProxyTransactionId(); - Message message = GrpcConverterV2.buildMessage(checkData.getMessageExt()); + Message message = GrpcConverter.buildMessage(checkData.getMessageExt()); TelemetryCommand response = TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand( RecoverOrphanedTransactionCommand.newBuilder() @@ -101,7 +101,7 @@ public class TransactionService extends BaseService implements TransactionStateC EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); this.forwardProducer.endTransaction(brokerAddr, requestHeader); future.complete(EndTransactionResponse.newBuilder() - .setStatus(ResponseBuilderV2.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build()); } catch (Throwable t) { future.completeExceptionally(t); @@ -110,9 +110,9 @@ public class TransactionService extends BaseService implements TransactionStateC } protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { - String topic = GrpcConverterV2.wrapResourceWithNamespace(request.getTopic()); + String topic = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); // use topic name as producerGroup - return GrpcConverterV2.buildEndTransactionRequestHeader(request, topic); + return GrpcConverter.buildEndTransactionRequestHeader(request, topic); } public void setCheckTransactionStateHook( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java index e1000961e2..929cab738c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/service/cluster/WriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java index ea3943a838..9d3b572bf8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java similarity index 93% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 98b96c123a..0971d9a341 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -15,39 +15,35 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service; +package org.apache.rocketmq.proxy.grpc.v2.service; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.ConsumerData; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.ProducerData; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryOffsetPolicy; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import apache.rocketmq.v1.SystemAttribute; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryOffsetPolicy; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; -import com.google.rpc.Code; import io.grpc.Context; import io.grpc.Metadata; import io.netty.channel.ChannelHandlerContext; @@ -77,7 +73,7 @@ import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -120,6 +116,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + metadata.put(InterceptorConstants.CLIENT_ID, "client-id"); } @Test @@ -130,18 +127,15 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .thenReturn(response); Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); HeartbeatRequest request = HeartbeatRequest.newBuilder() - .setClientId("test-client") - .setProducerData(ProducerData.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) + .setGroup(Resource.newBuilder() + .setName("group") .build()) .build(); CompletableFuture grpcFuture = localGrpcService.heartbeat( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); HeartbeatResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()) - .isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()) + .isEqualTo(Code.OK); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java index adae5ded25..f7d0e9a98d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java similarity index 99% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 2316e32c14..0a8c76a3a5 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java index e44bfa595d..167ff99027 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultReadQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.Broker; import apache.rocketmq.v1.Partition; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java index 222c64477b..c7aff6cd7f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/DefaultWriteQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.Broker; import apache.rocketmq.v1.Message; @@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java similarity index 96% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index aadad7a29e..fee3efce17 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.ConsumeMessageType; import apache.rocketmq.v1.ConsumeModel; @@ -23,8 +23,8 @@ import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.grpc.adapter.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 2ede5723fd..944ecce038 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.Message; import apache.rocketmq.v1.Resource; @@ -31,7 +31,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v1.adapter.ProxyException; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java index 83cac79eb7..b5cee9bbb9 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/PullMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.Broker; import apache.rocketmq.v1.FilterExpression; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java similarity index 99% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 896c79d36f..395f30b0c7 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; @@ -40,7 +40,7 @@ import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.proxy.grpc.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java similarity index 96% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index 73f243b7b0..cb108e7e83 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -1,4 +1,4 @@ -package org.apache.rocketmq.proxy.grpc.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v1.EndTransactionRequest; import apache.rocketmq.v1.EndTransactionResponse; @@ -11,7 +11,7 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.grpc.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.assertj.core.util.Lists; import org.junit.Test; diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java index a996584ccc..9a04cfcf63 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java @@ -13,9 +13,9 @@ import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v1.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.v1.service.ClusterGrpcService; +import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; import org.apache.rocketmq.test.base.GrpcBaseTest; import org.junit.After; import org.junit.Before; diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java index 1295f0115c..eaf285ac87 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java @@ -26,8 +26,8 @@ import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.service.LocalGrpcService; +import org.apache.rocketmq.proxy.grpc.v1.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; import org.apache.rocketmq.test.base.GrpcBaseTest; import org.junit.After; import org.junit.Before; From e5466e2b602b8659b9b80f06b50143745661ac79 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 7 Apr 2022 17:25:26 +0800 Subject: [PATCH 088/338] [ISSUE #3949] Support v2 --- .../grpc/v2/adapter/ResponseBuilder.java | 71 +++---- .../grpc/v2/service/cluster/BaseService.java | 4 +- .../v2/service/cluster/ConsumerService.java | 2 +- .../grpc/v2/service/cluster/RouteService.java | 7 +- .../grpc/v2/service/LocalGrpcServiceTest.java | 61 +++--- .../{proxy => grpc/v1}/ClusterGrpcTest.java | 20 +- .../test/{base => grpc/v1}/GrpcBaseTest.java | 5 +- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 187 ++++++++++++++++++ .../{proxy => grpc/v2}/LocalGrpcTest.java | 17 +- 9 files changed, 279 insertions(+), 95 deletions(-) rename test/src/test/java/org/apache/rocketmq/test/{proxy => grpc/v1}/ClusterGrpcTest.java (84%) rename test/src/test/java/org/apache/rocketmq/test/{base => grpc/v1}/GrpcBaseTest.java (98%) create mode 100644 test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java rename test/src/test/java/org/apache/rocketmq/test/{proxy => grpc/v2}/LocalGrpcTest.java (89%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index 487a526007..8c2fc13dd6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -37,69 +37,50 @@ public class ResponseBuilder { } public static Code buildCode(int remotingResponseCode) { - Code code; switch (remotingResponseCode) { case ResponseCode.SUCCESS: - case ResponseCode.NO_MESSAGE: { - code = Code.OK; - break; - } - case ResponseCode.SYSTEM_ERROR: { - code = Code.INTERNAL_SERVER_ERROR; - break; + case ResponseCode.NO_MESSAGE: + case ResponseCode.PULL_RETRY_IMMEDIATELY: { + return Code.OK; } case ResponseCode.SYSTEM_BUSY: case ResponseCode.POLLING_FULL: { - code = Code.TOO_MANY_REQUESTS; - break; + return Code.TOO_MANY_REQUESTS; } case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { - code = Code.UNRECOGNIZED; - break; + return Code.UNRECOGNIZED; } - case ResponseCode.MESSAGE_ILLEGAL: - case ResponseCode.VERSION_NOT_SUPPORTED: - case ResponseCode.SUBSCRIPTION_PARSE_FAILED: - case ResponseCode.FILTER_DATA_NOT_EXIST: { - code = Code.INVALID_ARGUMENT; - break; + case ResponseCode.MESSAGE_ILLEGAL: { + return Code.ILLEGAL_MESSAGE; } - case ResponseCode.SERVICE_NOT_AVAILABLE: - case ResponseCode.SLAVE_NOT_AVAILABLE: - case ResponseCode.PULL_RETRY_IMMEDIATELY: - case ResponseCode.PULL_OFFSET_MOVED: - case ResponseCode.SUBSCRIPTION_NOT_LATEST: - case ResponseCode.FILTER_DATA_NOT_LATEST: { - code = Code.UNAVAILABLE; - break; + case ResponseCode.VERSION_NOT_SUPPORTED: { + return Code.VERSION_UNSUPPORTED; + } + case ResponseCode.SLAVE_NOT_AVAILABLE: { + return Code.HA_NOT_AVAILABLE; + } + case ResponseCode.PULL_OFFSET_MOVED: { + return Code.ILLEGAL_MESSAGE_OFFSET; } case ResponseCode.NO_PERMISSION: { - code = Code.PERMISSION_DENIED; - break; + return Code.FORBIDDEN; } - case ResponseCode.TOPIC_NOT_EXIST: - code = Code.TOPIC_NOT_FOUND; - break; - case ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST: - case ResponseCode.SUBSCRIPTION_NOT_EXIST: - case ResponseCode.PULL_NOT_FOUND: - case ResponseCode.QUERY_NOT_FOUND: - case ResponseCode.CONSUMER_NOT_ONLINE: { - code = Code.NOT_FOUND; - break; + case ResponseCode.TOPIC_NOT_EXIST: { + return Code.TOPIC_NOT_FOUND; + } + case ResponseCode.PULL_NOT_FOUND: { + return Code.MESSAGE_NOT_FOUND; + } + case ResponseCode.FLUSH_DISK_TIMEOUT: { + return Code.MASTER_PERSISTENCE_TIMEOUT; } - case ResponseCode.POLLING_TIMEOUT: - case ResponseCode.FLUSH_DISK_TIMEOUT: case ResponseCode.FLUSH_SLAVE_TIMEOUT: { - code = Code.DEADLINE_EXCEEDED; - break; + return Code.SLAVE_PERSISTENCE_TIMEOUT; } default: { - code = Code.INTERNAL_SERVER_ERROR; + return Code.INTERNAL_SERVER_ERROR; } - } - return code; } public static String buildMessage(int responseCode, String remark) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java index 758c1ba9db..835e31f6b8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java @@ -44,11 +44,11 @@ public class BaseService { protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { if (StringUtils.isBlank(brokerName)) { - throw new ProxyException(Code.INVALID_ARGUMENT, "broker name is empty"); + throw new ProxyException(Code.UNRECOGNIZED, "broker name is empty"); } String addr = this.connectorManager.getTopicRouteCache().getBrokerAddr(brokerName); if (StringUtils.isBlank(addr)) { - throw new ProxyException(Code.NOT_FOUND, brokerName + " not exist"); + throw new ProxyException(Code.UNRECOGNIZED, brokerName + " not exist"); } return addr; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 322e670350..d696dd07bd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -249,7 +249,7 @@ public class ConsumerService extends BaseService { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - Settings settings = GrpcClientManager.getClientSettings(ctx); + Settings settings = GrpcClientManager.getClientSettings(ctx).getSettings(); int maxDeliveryAttempts = settings.getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 8da26d154e..83322e2400 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -20,6 +20,7 @@ import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.Assignment; import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.MessageQueue; @@ -51,6 +52,7 @@ import org.apache.rocketmq.proxy.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; public class RouteService extends BaseService { private final ProxyMode mode; @@ -238,11 +240,12 @@ public class RouteService extends BaseService { } } if (ProxyMode.isClusterMode(mode)) { - Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, request.getEndpoints()); + ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - request.getEndpoints() + " is invalidate")) + clientSettings.getAccessPoint() + " is invalidate")) .build()); return future; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 0971d9a341..f3e276c91f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -29,6 +29,7 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; @@ -42,6 +43,7 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import io.grpc.Context; @@ -73,8 +75,8 @@ import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.store.MessageStore; @@ -146,18 +148,15 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .thenReturn(response); Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); HeartbeatRequest request = HeartbeatRequest.newBuilder() - .setClientId("test-client") - .setConsumerData(ConsumerData.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) + .setGroup(Resource.newBuilder() + .setName("group") .build()) .build(); CompletableFuture grpcFuture = localGrpcService.heartbeat( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); HeartbeatResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()) - .isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()) + .isEqualTo(Code.OK); } @Test @@ -167,8 +166,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(response); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setSystemAttribute(SystemAttribute.newBuilder() + .setMessages(0, Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) .build()) @@ -177,8 +176,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.sendMessage( Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); SendMessageResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()) - .isEqualTo(Code.INTERNAL.getNumber()); + assertThat(r.getStatus().getCode()) + .isEqualTo(Code.INTERNAL_SERVER_ERROR); } @Test @@ -186,8 +185,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(null); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setSystemAttribute(SystemAttribute.newBuilder() + .setMessages(0, Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) .build()) @@ -203,8 +202,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenThrow(new RemotingCommandException("test")); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setSystemAttribute(SystemAttribute.newBuilder() + .setMessages(0, Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) .build()) @@ -241,7 +240,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(remotingCommand); ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -254,7 +253,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))), request); ReceiveMessageResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getMessagesCount()).isEqualTo(1); assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); @@ -300,7 +299,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); AckMessageResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @Test @@ -333,7 +332,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); NackMessageResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @Test @@ -361,7 +360,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); ForwardMessageToDeadLetterQueueResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @Test @@ -385,7 +384,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); EndTransactionResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @Test @@ -401,7 +400,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(messageStore.getOffsetInQueueByTime(Mockito.eq(topic), Mockito.eq(queueId), Mockito.anyLong())).thenReturn(timeOffset); QueryOffsetRequest request = QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -414,11 +413,11 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); QueryOffsetResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getOffset()).isEqualTo(0); request = QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -431,11 +430,11 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getOffset()).isEqualTo(maxOffset); request = QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -451,7 +450,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getOffset()).isEqualTo(timeOffset); } @@ -470,7 +469,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.any(RemotingCommand.class))) .thenReturn(response); NotifyClientTerminationRequest request = NotifyClientTerminationRequest.newBuilder() - .setProducerGroup(Resource.newBuilder() + .setGroup(Resource.newBuilder() .setName("group") .build()) .build(); @@ -515,7 +514,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withValue(InterceptorConstants.METADATA, metadata) .attach(), request); ChangeInvisibleDurationResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); ReceiptHandle handle = ReceiptHandle.decode(r.getReceiptHandle()); assertThat(handle.getInvisibleTime()).isEqualTo(invisibleTime); assertThat(handle.getQueueId()).isEqualTo(queueId); @@ -554,7 +553,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))), request); PullMessageResponse r = grpcFuture.get(); - assertThat(r.getCommon().getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getMessagesCount()).isEqualTo(1); assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java similarity index 84% rename from test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java index 9a04cfcf63..5d40e39e29 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java @@ -1,4 +1,21 @@ -package org.apache.rocketmq.test.proxy; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.test.grpc.v1; import apache.rocketmq.v1.AckMessageResponse; import apache.rocketmq.v1.Address; @@ -16,7 +33,6 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v1.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.v1.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; -import org.apache.rocketmq.test.base.GrpcBaseTest; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java similarity index 98% rename from test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java index 2739348ab4..5494f5405d 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.test.base; +package org.apache.rocketmq.test.grpc.v1; import apache.rocketmq.v1.AckMessageRequest; import apache.rocketmq.v1.AckMessageResponse; @@ -49,11 +49,10 @@ import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; import java.security.cert.CertificateException; import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.function.Supplier; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; +import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; import static org.assertj.core.api.Assertions.assertThat; diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java new file mode 100644 index 0000000000..7760be6458 --- /dev/null +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.test.grpc.v2; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SystemProperties; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import io.grpc.Channel; +import io.grpc.ServerInterceptors; +import io.grpc.ServerServiceDefinition; +import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; +import io.grpc.testing.GrpcCleanupRule; +import io.netty.handler.ssl.ApplicationProtocolNames; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.handler.ssl.util.SelfSignedCertificate; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; +import org.apache.rocketmq.test.base.BaseConf; +import org.junit.Rule; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GrpcBaseTest extends BaseConf { + /** + * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. + */ + @Rule + public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + private static final int defaultQueueNums = 8; + + protected Channel setUpServer(MessagingServiceGrpc.MessagingServiceImplBase serverImpl, + int port, boolean enableInterceptor) throws IOException, CertificateException { + SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(serverImpl); + if (enableInterceptor) { + serviceDefinition = ServerInterceptors.intercept(serverImpl, new ContextInterceptor(), new HeaderInterceptor()); + } + // Create a server, add service, start, and register for automatic graceful shutdown. + grpcCleanup.register(NettyServerBuilder.forPort(port) + .directExecutor() + .addService(serviceDefinition) + .useTransportSecurity(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .build() + .start()); + // Create a client channel and register for automatic graceful shutdown. + return grpcCleanup.register(NettyChannelBuilder.forAddress("127.0.0.1", port) + .directExecutor() + .sslContext(SslContextBuilder + .forClient() + .sslProvider(SslProvider.OPENSSL) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .applicationProtocolConfig(new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2)) + .build() + ) + .build()); + } + + public QueryRouteRequest buildQueryRouteRequest(String topic) { + return buildQueryRouteRequest(topic, Endpoints.getDefaultInstance()); + } + + public QueryRouteRequest buildQueryRouteRequest(String topic, Endpoints endpoints) { + return QueryRouteRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setEndpoints(endpoints) + .build(); + } + + public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { + return SendMessageRequest.newBuilder() + .setMessages(0, Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(messageId) + .setQueueId(0) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build(); + } + + public ReceiveMessageRequest buildReceiveMessageRequest(String group, String topic) { + return ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .setMessageQueue(MessageQueue.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setId(0) + .build()) + .setBatchSize(16) + .setInvisibleDuration(Duration.newBuilder() + .setSeconds(3) + .build()) + .setInitializationTimestamp(Timestamp.newBuilder() + .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) + .build()) + .build(); + } + + public AckMessageRequest buildAckMessageRequest(String group, String topic, String receiptHandle) { + return AckMessageRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setReceiptHandle(receiptHandle) + .build(); + } + + public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getMessageQueuesList().size()).isEqualTo(brokerSize * defaultQueueNums); + assertThat(response.getMessageQueues(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); + } + + public void assertSendMessage(SendMessageResponse response, String messageId) { + assertThat(response.getStatus() + .getCode()).isEqualTo(Code.OK); + assertThat(response.getReceipts(0).getMessageId()).isEqualTo(messageId); + } + + public void assertReceiveMessage(ReceiveMessageResponse response, String messageId) { + assertThat(response.getStatus() + .getCode()).isEqualTo(Code.OK); + assertThat(response.getMessagesCount()).isEqualTo(1); + assertThat(response.getMessages(0) + .getSystemProperties() + .getMessageId()).isEqualTo(messageId); + } + + public void assertAck(AckMessageResponse response) { + assertThat(response.getStatus() + .getCode()).isEqualTo(Code.OK); + } +} \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java similarity index 89% rename from test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index eaf285ac87..3b2610848e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/proxy/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -15,20 +15,19 @@ * limitations under the License. */ -package org.apache.rocketmq.test.proxy; +package org.apache.rocketmq.test.grpc.v2; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.MessagingServiceGrpc; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.SendMessageResponse; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageResponse; import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.v1.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; -import org.apache.rocketmq.test.base.GrpcBaseTest; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -82,7 +81,7 @@ public class LocalGrpcTest extends GrpcBaseTest { ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); + String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); assertAck(ackMessageResponse); } From 4b4cedc980ee5ccf24eb80bbb98aafce63e1b1d3 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 8 Apr 2022 16:09:43 +0800 Subject: [PATCH 089/338] [ISSUE #3949] Support v2 Implement v2 Local mode Add V2Converter for Cluster mode --- .../proxy/grpc/v1/adapter/V2Converter.java | 68 ++++++++++++++++ .../grpc/v1/service/ClusterGrpcService.java | 79 +++---------------- .../grpc/v2/adapter/ResponseBuilder.java | 6 +- .../grpc/v2/service/ClusterGrpcService.java | 6 +- .../grpc/v2/service/GrpcClientManager.java | 14 +--- .../grpc/v2/service/LocalGrpcService.java | 23 +++--- .../v2/service/cluster/ConsumerService.java | 10 ++- .../grpc/v2/service/cluster/RouteService.java | 11 ++- .../grpc/v2/service/LocalGrpcServiceTest.java | 57 +++++++++---- 9 files changed, 162 insertions(+), 112 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java new file mode 100644 index 0000000000..64ce1275db --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v1.adapter; + +import apache.rocketmq.v1.ResponseCommon; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Status; + +public class V2Converter { + public static Resource buildResource(apache.rocketmq.v1.Resource resource) { + return Resource.newBuilder() + .setName(resource.getName()) + .setResourceNamespace(resource.getResourceNamespace()) + .build(); + } + + public static HeartbeatRequest buildHeartbeatRequest(apache.rocketmq.v1.HeartbeatRequest request) { + Resource group; + if (request.hasProducerData()) { + group = buildResource(request.getProducerData().getGroup()); + } else if (request.hasConsumerData()) { + group = buildResource(request.getConsumerData().getGroup()); + } else { + throw new IllegalArgumentException("HeartbeatRequest is not valid"); + } + return HeartbeatRequest.newBuilder() + .setGroup(group) + .build(); + } + + public static apache.rocketmq.v1.HeartbeatResponse buildHeartbeatResponse(HeartbeatResponse response) { + return apache.rocketmq.v1.HeartbeatResponse.newBuilder() + .setCommon(ResponseCommon.newBuilder() + .setStatus(buildStatus(response.getStatus())) + .build()) + .build(); + } + + public static com.google.rpc.Status buildStatus(Status status) { + return com.google.rpc.Status.newBuilder() + .setCode(buildCodeValue(status.getCode())) + .setMessage(status.getMessage()) + .build(); + } + + public static int buildCodeValue(Code code) { + // TODO: complete code mapping + return com.google.rpc.Code.OK_VALUE; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java index 94b1e56798..1aed35126d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java @@ -54,57 +54,22 @@ import apache.rocketmq.v1.SendMessageResponse; import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.PullMessageService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; +import org.apache.rocketmq.proxy.grpc.v1.adapter.V2Converter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread")); - - private final ChannelManager channelManager; - private final ConnectorManager connectorManager; - private final ProducerService producerService; - private final ConsumerService receiveMessageService; - private final RouteService routeService; - private final ForwardClientService clientService; - private final PullMessageService pullMessageService; - private final TransactionService transactionService; - private final PollResponseManager pollCommandResponseManager; + private final org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService clusterGrpcService; public ClusterGrpcService() { - this.channelManager = new ChannelManager(); - this.pollCommandResponseManager = new PollResponseManager(); - this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); - this.receiveMessageService = new ConsumerService(connectorManager); - this.producerService = new ProducerService(connectorManager); - this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); - this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); - this.pullMessageService = new PullMessageService(connectorManager); - this.transactionService = new TransactionService(connectorManager, channelManager); + this.clusterGrpcService = new org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService();; - this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); - this.appendStartAndShutdown(this.connectorManager); + this.appendStartAndShutdown(clusterGrpcService); } @Override @@ -114,12 +79,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - this.clientService.heartbeat(ctx, request); - return CompletableFuture.completedFuture( - HeartbeatResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build() - ); + return clusterGrpcService.heartbeat(ctx, V2Converter.buildHeartbeatRequest(request)) + .thenApply(V2Converter::buildHeartbeatResponse); } @Override @@ -158,7 +119,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { + ForwardMessageToDeadLetterQueueRequest request) { return null; } @@ -179,7 +140,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - return this.clientService.pollCommand(ctx, request); + return null; } @Override @@ -190,14 +151,13 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture reportMessageConsumptionResult(Context ctx, - ReportMessageConsumptionResultRequest request) { + ReportMessageConsumptionResultRequest request) { return null; } @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - this.clientService.unregister(ctx, request); return CompletableFuture.completedFuture( NotifyClientTerminationResponse.newBuilder() .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) @@ -210,25 +170,4 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc ChangeInvisibleDurationRequest request) { return null; } - - private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { - - @Override - public void start() throws Exception { - - } - - @Override - public void shutdown() throws Exception { - scheduledExecutorService.shutdown(); - } - } - - private class GrpcTransactionStateChecker implements TransactionStateChecker { - - @Override - public void checkTransactionState(TransactionStateCheckRequest checkData) { - transactionService.checkTransactionState(checkData); - } - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index 8c2fc13dd6..eecc19f53c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -30,9 +30,13 @@ public class ResponseBuilder { } public static Status buildStatus(int remotingResponseCode, String remark) { + String message = remark; + if (message == null) { + message = String.valueOf(remotingResponseCode); + } return Status.newBuilder() .setCode(buildCode(remotingResponseCode)) - .setMessage(remark) + .setMessage(message) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index e8454971ff..515039b263 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -83,14 +83,16 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final PullMessageService pullMessageService; private final TransactionService transactionService; private final PollResponseManager pollCommandResponseManager; + private final GrpcClientManager grpcClientManager; public ClusterGrpcService() { this.channelManager = new ChannelManager(); + this.grpcClientManager = new GrpcClientManager(); this.pollCommandResponseManager = new PollResponseManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); - this.consumerService = new ConsumerService(connectorManager); + this.consumerService = new ConsumerService(connectorManager, grpcClientManager); this.producerService = new ProducerService(connectorManager); - this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager); + this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager, grpcClientManager); this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index 8371d2eaee..eb86c41cfc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -18,24 +18,18 @@ package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.ClientSettings; -import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); - public static ClientSettings getClientSettings(Context ctx) { - return CLIENT_SETTINGS_MAP.get(getClientId(ctx)); + public ClientSettings getClientSettings(String clientId) { + return CLIENT_SETTINGS_MAP.get(clientId); } - public static void updateClientSettings(Context ctx, ClientSettings clientSettings) { - CLIENT_SETTINGS_MAP.put(getClientId(ctx), clientSettings); - } - - public static String getClientId(Context ctx) { - return InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + public void updateClientSettings(String clientId, ClientSettings clientSettings) { + CLIENT_SETTINGS_MAP.put(clientId, clientSettings); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 48f3169e30..730ef5ea0f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -122,6 +122,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; private final PollResponseManager pollCommandResponseManager; + private final GrpcClientManager grpcClientManager; private final RouteService routeService; private final DelayPolicy delayPolicy; @@ -131,7 +132,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo // TransactionStateChecker is not used in Local mode. ConnectorManager connectorManager = new ConnectorManager(null); this.pollCommandResponseManager = new PollResponseManager(); - this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager); + this.grpcClientManager = new GrpcClientManager(); + this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.appendStartAndShutdown(connectorManager); this.appendStartAndShutdown(new LocalGrpcServiceStartAndShutdown()); @@ -146,10 +148,10 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { LanguageCode languageCode; String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); languageCode = LanguageCode.valueOf(language); - String clientId = GrpcClientManager.getClientId(ctx); - ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -239,7 +241,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); - ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -457,8 +460,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo NotifyClientTerminationRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - String clientId = GrpcClientManager.getClientId(ctx); - ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); @@ -512,27 +515,27 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); return new StreamObserver() { @Override public void onNext(TelemetryCommand request) { switch (request.getCommandCase()) { case CLIENT_SETTINGS: { ClientSettings clientSettings = request.getClientSettings(); - GrpcClientManager.updateClientSettings(ctx, clientSettings); - String clientId = GrpcClientManager.getClientId(ctx); + grpcClientManager.updateClientSettings(clientId, clientSettings); Settings settings = clientSettings.getSettings(); if (settings.hasPublishing()) { Publishing publishing = settings.getPublishing(); for (Resource topic : publishing.getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(channelManager, topicName, clientId); + GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { Subscription subscription = settings.getSubscription(); String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(channelManager, groupName, clientId); + GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); consumerChannel.setClientObserver(responseObserver); } responseObserver.onNext(TelemetryCommand.newBuilder() diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index d696dd07bd..7267b78b85 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -48,6 +48,7 @@ import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.common.DelayPolicy; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; @@ -70,7 +71,9 @@ public class ConsumerService extends BaseService { private volatile ResponseHook ackMessageHook; private volatile ResponseHook nackMessageResponseResponseHook; - public ConsumerService(ConnectorManager connectorManager) { + private final GrpcClientManager grpcClientManager; + + public ConsumerService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); @@ -78,6 +81,8 @@ public class ConsumerService extends BaseService { this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); this.delayPolicy = DelayPolicy.build(ConfigurationManager.getProxyConfig().getMessageDelayLevel()); + + this.grpcClientManager = grpcClientManager; } public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { @@ -246,10 +251,11 @@ public class ConsumerService extends BaseService { } }); try { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - Settings settings = GrpcClientManager.getClientSettings(ctx).getSettings(); + Settings settings = grpcClientManager.getClientSettings(clientId).getSettings(); int maxDeliveryAttempts = settings.getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 83322e2400..d107b093a4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -42,13 +42,14 @@ import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.common.ParameterConverter; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.common.ParameterConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; @@ -64,13 +65,16 @@ public class RouteService extends BaseService { private volatile AssignmentQueueSelector assignmentQueueSelector; private volatile ResponseHook queryAssignmentHook; - public RouteService(ProxyMode mode, ConnectorManager connectorManager) { + private GrpcClientManager grpcClientManager; + + public RouteService(ProxyMode mode, ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { super(connectorManager); Preconditions.checkArgument(ProxyMode.isClusterMode(mode) || ProxyMode.isLocalMode(mode)); this.mode = mode; queryRouteEndpointConverter = (ctx, parameter) -> parameter; queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); + this.grpcClientManager = grpcClientManager; } public void setQueryRouteEndpointConverter(ParameterConverter queryRouteEndpointConverter) { @@ -240,7 +244,8 @@ public class RouteService extends BaseService { } } if (ProxyMode.isClusterMode(mode)) { - ClientSettings clientSettings = GrpcClientManager.getClientSettings(ctx); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index f3e276c91f..9e2f51b79f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -21,6 +21,8 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; @@ -33,6 +35,7 @@ import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryOffsetPolicy; @@ -43,11 +46,14 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.SystemProperties; +import apache.rocketmq.v2.TelemetryCommand; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.Metadata; +import io.grpc.stub.StreamObserver; import io.netty.channel.ChannelHandlerContext; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; @@ -105,6 +111,8 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { private Metadata metadata; + private StreamObserver streamObserver; + @Before public void setUp() throws Throwable { super.before(); @@ -119,10 +127,35 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.CLIENT_ID, "client-id"); + Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(); + streamObserver = localGrpcService.telemetry(Context.current(), new StreamObserver() { + @Override public void onNext(TelemetryCommand value) { + } + + @Override public void onError(Throwable t) { + } + + @Override public void onCompleted() { + } + }); + streamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(ClientSettings.newBuilder().setSettings(Settings.getDefaultInstance())) + .build()); } @Test public void testHeartbeatProducerData() throws Exception { + streamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(ClientSettings.newBuilder() + .setSettings(Settings.newBuilder() + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder() + .setName("topic") + .build()) + .build()) + .build()) + .setClientType(ClientType.PRODUCER).build()) + .build()); RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) @@ -133,8 +166,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .setName("group") .build()) .build(); - CompletableFuture grpcFuture = localGrpcService.heartbeat( - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + CompletableFuture grpcFuture = localGrpcService.heartbeat(Context.current(), request); HeartbeatResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()) .isEqualTo(Code.OK); @@ -142,6 +174,10 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testHeartbeatConsumerData() throws Exception { + streamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(ClientSettings.newBuilder() + .setClientType(ClientType.PUSH_CONSUMER).build()) + .build()); RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) @@ -152,8 +188,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .setName("group") .build()) .build(); - CompletableFuture grpcFuture = localGrpcService.heartbeat( - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + CompletableFuture grpcFuture = localGrpcService.heartbeat(Context.current(), request); HeartbeatResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()) .isEqualTo(Code.OK); @@ -166,7 +201,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(response); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessages(0, Message.newBuilder() + .addMessages(0, Message.newBuilder() .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) @@ -185,7 +220,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(null); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessages(0, Message.newBuilder() + .addMessages(0, Message.newBuilder() .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) @@ -202,7 +237,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenThrow(new RemotingCommandException("test")); SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessages(0, Message.newBuilder() + .addMessages(0, Message.newBuilder() .setSystemProperties(SystemProperties.newBuilder() .setMessageId("123") .build()) @@ -249,7 +284,6 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { CompletableFuture grpcFuture = localGrpcService.receiveMessage( Context.current() .withValue(InterceptorConstants.METADATA, metadata) - .attach() .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))), request); ReceiveMessageResponse r = grpcFuture.get(); @@ -267,8 +301,6 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder().getDefaultInstanceForType(); CompletableFuture grpcFuture = localGrpcService.receiveMessage( Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach() .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("test"))), request); assertThat(grpcFuture.isDone()).isFalse(); @@ -408,10 +440,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build()) .setPolicy(QueryOffsetPolicy.BEGINNING) .build(); - CompletableFuture grpcFuture = localGrpcService.queryOffset( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + CompletableFuture grpcFuture = localGrpcService.queryOffset(Context.current(), request); QueryOffsetResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); assertThat(r.getOffset()).isEqualTo(0); From 2da929357553acbdd6a0f64932486cd12b4fe9c2 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 8 Apr 2022 17:02:03 +0800 Subject: [PATCH 090/338] [ISSUE #3949] Refector by code review * Add toString for MetadataHeader * Use RemotingHelper * Use Map in RequestMapping * Add Epoll in GrpcServer --- .../rocketmq/acl/common/MetadataHeader.java | 32 +++--- .../acl/plain/PlainAccessValidator.java | 3 +- .../rocketmq/proxy/config/ProxyConfig.java | 9 ++ .../rocketmq/proxy/grpc/GrpcServer.java | 25 +++-- .../proxy/grpc/v2/adapter/RequestMapping.java | 105 +++++++++--------- 5 files changed, 96 insertions(+), 78 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java index a6824918a3..96c7ac7790 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java @@ -122,21 +122,6 @@ public class MetadataHeader { this.datetime, this.sessionToken, this.requestId, this.language, this.clientVersion, this.protocol, this.requestCode); } - - @Override public String toString() { - return "MetadataHeaderBuilder{" + "remoteAddress='" + remoteAddress + '\'' + - ", tenantId='" + tenantId + '\'' + - ", namespace='" + namespace + '\'' + - ", authorization='" + authorization + '\'' + - ", datetime='" + datetime + '\'' + - ", sessionToken='" + sessionToken + '\'' + - ", requestId='" + requestId + '\'' + - ", language='" + language + '\'' + - ", clientVersion='" + clientVersion + '\'' + - ", protocol='" + protocol + '\'' + - ", requestCode=" + requestCode + - '}'; - } } public static MetadataHeader.MetadataHeaderBuilder builder() { @@ -230,4 +215,21 @@ public class MetadataHeader { public void setRequestCode(int requestCode) { this.requestCode = requestCode; } + + @Override public String toString() { + final StringBuilder sb = new StringBuilder("MetadataHeader{"); + sb.append("remoteAddress='").append(remoteAddress).append('\''); + sb.append(", tenantId='").append(tenantId).append('\''); + sb.append(", namespace='").append(namespace).append('\''); + sb.append(", authorization='").append(authorization).append('\''); + sb.append(", datetime='").append(datetime).append('\''); + sb.append(", sessionToken='").append(sessionToken).append('\''); + sb.append(", requestId='").append(requestId).append('\''); + sb.append(", language='").append(language).append('\''); + sb.append(", clientVersion='").append(clientVersion).append('\''); + sb.append(", protocol='").append(protocol).append('\''); + sb.append(", requestCode=").append(requestCode); + sb.append('}'); + return sb.toString(); + } } diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index 6e1f78463e..cf16b347d5 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -53,6 +53,7 @@ import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHea import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import static org.apache.rocketmq.acl.plain.PlainAccessResource.getRetryTopic; @@ -156,7 +157,7 @@ public class PlainAccessValidator implements AccessValidator { PlainAccessResource accessResource = new PlainAccessResource(); String remoteAddress = header.getRemoteAddress(); if (remoteAddress != null && remoteAddress.contains(":")) { - accessResource.setWhiteRemoteAddress(remoteAddress.substring(0, remoteAddress.lastIndexOf(':'))); + accessResource.setWhiteRemoteAddress(RemotingHelper.parseHostFromAddress(remoteAddress)); } else { accessResource.setWhiteRemoteAddress(remoteAddress); } 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 37b4281430..1375abc3e7 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 @@ -47,6 +47,7 @@ public class ProxyConfig { private String grpcTlsCertPath = ConfigurationManager.getProxyHome() + "/conf/tls/gRPC.chain.cert.pem"; private int grpcBossLoopNum = 1; private int grpcWorkerLoopNum = Runtime.getRuntime().availableProcessors() * 2; + private boolean enableGrpcEpoll = false; private int grpcThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2; private int grpcThreadPoolQueueCapacity = 100000; private String brokerConfigPath = ConfigurationManager.getProxyHome() + "/conf/broker.conf"; @@ -196,6 +197,14 @@ public class ProxyConfig { this.grpcWorkerLoopNum = grpcWorkerLoopNum; } + public boolean isEnableGrpcEpoll() { + return enableGrpcEpoll; + } + + public void setEnableGrpcEpoll(boolean enableGrpcEpoll) { + this.enableGrpcEpoll = enableGrpcEpoll; + } + public int getGrpcThreadPoolNums() { return grpcThreadPoolNums; } 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 9b22e8d07b..2167ac08cd 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 @@ -19,6 +19,8 @@ package org.apache.rocketmq.proxy.grpc; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel; import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup; import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; @@ -39,8 +41,8 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,12 +93,21 @@ public class GrpcServer implements StartAndShutdown { int workerLoopNum = ConfigurationManager.getProxyConfig().getGrpcWorkerLoopNum(); int maxInboundMessageSize = ConfigurationManager.getProxyConfig().getGrpcMaxInboundMessageSize(); - serverBuilder.maxInboundMessageSize(maxInboundMessageSize) - .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) - .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) - .channelType(NioServerSocketChannel.class) - .addService(messagingProcessor) - .executor(this.executor); + if (ConfigurationManager.getProxyConfig().isEnableGrpcEpoll()) { + serverBuilder.maxInboundMessageSize(maxInboundMessageSize) + .bossEventLoopGroup(new EpollEventLoopGroup(bossLoopNum)) + .workerEventLoopGroup(new EpollEventLoopGroup(workerLoopNum)) + .channelType(EpollServerSocketChannel.class) + .addService(messagingProcessor) + .executor(this.executor); + } else { + serverBuilder.maxInboundMessageSize(maxInboundMessageSize) + .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) + .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) + .channelType(NioServerSocketChannel.class) + .addService(messagingProcessor) + .executor(this.executor); + } // grpc interceptors, including acl, logging etc. if (ConfigurationManager.getProxyConfig().isEnableACL()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index fe00bd12a4..2a25ff8eb7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -17,65 +17,60 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.SendMessageRequest; +import java.util.HashMap; +import java.util.Map; import org.apache.rocketmq.common.protocol.RequestCode; public class RequestMapping { + private final static Map REQUEST_MAP = new HashMap() {{ + // v2 + put(QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); + put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); + put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); + put(PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); + put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + + // v1 + put(apache.rocketmq.v1.QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(apache.rocketmq.v1.HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(apache.rocketmq.v1.HealthCheckRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(apache.rocketmq.v1.SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); + put(apache.rocketmq.v1.QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(apache.rocketmq.v1.ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(apache.rocketmq.v1.AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); + put(apache.rocketmq.v1.NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); + put(apache.rocketmq.v1.PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(apache.rocketmq.v1.NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); + put(apache.rocketmq.v1.ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + }}; + public static int map(String rpcFullName) { - if (QueryRouteRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.GET_ROUTEINFO_BY_TOPIC; - } - if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.HEART_BEAT; - } - if (HealthCheckRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.HEART_BEAT; - } - if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.SEND_MESSAGE_V2; - } - if (QueryAssignmentRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.GET_ROUTEINFO_BY_TOPIC; - } - if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.PULL_MESSAGE; - } - if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.UPDATE_CONSUMER_OFFSET; - } - if (NackMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.CONSUMER_SEND_MSG_BACK; - } - if (ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.CONSUMER_SEND_MSG_BACK; - } - if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.END_TRANSACTION; - } - if (QueryOffsetRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.SEARCH_OFFSET_BY_TIMESTAMP; - } - if (PullMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.PULL_MESSAGE; - } - if (NotifyClientTerminationRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.UNREGISTER_CLIENT; - } - if (ChangeInvisibleDurationRequest.getDescriptor().getFullName().equals(rpcFullName)) { - return RequestCode.CONSUMER_SEND_MSG_BACK; + if (REQUEST_MAP.containsKey(rpcFullName)) { + return REQUEST_MAP.get(rpcFullName); } return RequestCode.HEART_BEAT; } From bc7fbfd46f538d298ba6a25091d4b21a3078a0b8 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 11 Apr 2022 15:00:15 +0800 Subject: [PATCH 091/338] [ISSUE #3949] Fix buildHeartbeatData * Use topic as producer group --- .../rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index d7286c57b4..5819ce6dcc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -106,17 +106,20 @@ public class GrpcConverter { ClientSettings clientSettings) { HeartbeatData heartbeatData = new HeartbeatData(); heartbeatData.setClientID(clientId); - String groupName = wrapResourceWithNamespace(request.getGroup()); switch (clientSettings.getClientType()) { case PRODUCER: { Set producerDataSet = new HashSet<>(); - producerDataSet.add(buildProducerData(groupName)); + for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + String topicName = wrapResourceWithNamespace(topic); + producerDataSet.add(buildProducerData(topicName)); + } heartbeatData.setProducerDataSet(producerDataSet); break; } case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { + String groupName = wrapResourceWithNamespace(request.getGroup()); Set consumerDataSet = new HashSet<>(); consumerDataSet.add(buildConsumerData(groupName, clientSettings)); heartbeatData.setConsumerDataSet(consumerDataSet); From f255f1bc3a38419b8fc751f9c470860c804c8e57 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 11 Apr 2022 15:49:48 +0800 Subject: [PATCH 092/338] [ISSUE #3949] Fix v2 endpoint for protocol --- .../proxy/grpc/v2/service/cluster/RouteService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index d107b093a4..2b240eca41 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -114,11 +114,13 @@ public class RouteService extends BaseService { List messageQueueList = new ArrayList<>(); if (ProxyMode.isClusterMode(mode.name())) { - Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, request.getEndpoints()); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - request.getEndpoints() + " is invalidate")) + clientSettings.getAccessPoint() + " is invalidate")) .build()); return future; } From 46ace3538072b3633112c0a0ebab6d858b1306dd Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 11 Apr 2022 15:59:35 +0800 Subject: [PATCH 093/338] [ISSUE #3949] v2 support --- .../grpc/v1/service/ClusterGrpcService.java | 2 +- .../grpc/v2/service/ClusterGrpcService.java | 11 +- .../v2/service/cluster/ConsumerService.java | 102 +++++++- .../service/cluster/ForwardClientService.java | 247 ++++++++++++------ .../service/cluster/TransactionService.java | 2 +- .../cluster/ForwardClientServiceTest.java | 4 +- 6 files changed, 267 insertions(+), 101 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java index 1aed35126d..f39857ba84 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java @@ -67,7 +67,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService clusterGrpcService; public ClusterGrpcService() { - this.clusterGrpcService = new org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService();; + this.clusterGrpcService = new org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService(); this.appendStartAndShutdown(clusterGrpcService); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 515039b263..e8caea4203 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -93,7 +93,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.consumerService = new ConsumerService(connectorManager, grpcClientManager); this.producerService = new ProducerService(connectorManager); this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager, grpcClientManager); - this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, pollCommandResponseManager); + this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, + channelManager, grpcClientManager, pollCommandResponseManager); this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); @@ -108,7 +109,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - return null; + return clientService.heartbeat(ctx, request); } @Override @@ -160,18 +161,18 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - return null; + return clientService.notifyClientTermination(ctx, request); } @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { - return null; + return consumerService.changeInvisibleDuration(ctx, request); } @Override public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { - return null; + return clientService.telemetry(ctx, responseObserver); } private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 7267b78b85..ac744b4b3c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -18,6 +18,8 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.NackMessageRequest; @@ -69,7 +71,8 @@ public class ConsumerService extends BaseService { private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackNoMatchedMessageHook; private volatile ResponseHook ackMessageHook; - private volatile ResponseHook nackMessageResponseResponseHook; + private volatile ResponseHook nackMessageHook; + private volatile ResponseHook changeInvisibleDurationHook; private final GrpcClientManager grpcClientManager; @@ -246,8 +249,8 @@ public class ConsumerService extends BaseService { public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { - if (nackMessageResponseResponseHook != null) { - nackMessageResponseResponseHook.beforeResponse(ctx, request, response, throwable); + if (nackMessageHook != null) { + nackMessageHook.beforeResponse(ctx, request, response, throwable); } }); try { @@ -323,19 +326,106 @@ public class ConsumerService extends BaseService { .build(); } + public CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (changeInvisibleDurationHook != null) { + changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); + } + }); + try { + ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); + + ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); + CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); + resultFuture + .thenAccept(result -> { + try { + future.complete(convertToChangeInvisibleDurationResponse(ctx, request, result)); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + }) + .exceptionally(throwable -> { + future.completeExceptionally(throwable); + return null; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, + ChangeInvisibleDurationRequest request) { + return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); + } + + protected ChangeInvisibleDurationResponse convertToChangeInvisibleDurationResponse(Context ctx, + ChangeInvisibleDurationRequest request, AckResult ackResult) { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return ChangeInvisibleDurationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setReceiptHandle(ackResult.getExtraInfo()) + .build(); + } + return ChangeInvisibleDurationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) + .build(); + } + + public ReadQueueSelector getReadQueueSelector() { + return readQueueSelector; + } + public void setReadQueueSelector(ReadQueueSelector readQueueSelector) { this.readQueueSelector = readQueueSelector; } - public void setReceiveMessageHook(ResponseHook receiveMessageHook) { + public ResponseHook getReceiveMessageHook() { + return receiveMessageHook; + } + + public void setReceiveMessageHook( + ResponseHook receiveMessageHook) { this.receiveMessageHook = receiveMessageHook; } - public void setAckNoMatchedMessageHook(ResponseHook ackNoMatchedMessageHook) { + public ResponseHook getAckNoMatchedMessageHook() { + return ackNoMatchedMessageHook; + } + + public void setAckNoMatchedMessageHook( + ResponseHook ackNoMatchedMessageHook) { this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; } - public void setAckMessageHook(ResponseHook ackMessageHook) { + public ResponseHook getAckMessageHook() { + return ackMessageHook; + } + + public void setAckMessageHook( + ResponseHook ackMessageHook) { this.ackMessageHook = ackMessageHook; } + + public ResponseHook getNackMessageHook() { + return nackMessageHook; + } + + public void setNackMessageHook( + ResponseHook nackMessageHook) { + this.nackMessageHook = nackMessageHook; + } + + public ResponseHook getChangeInvisibleDurationHook() { + return changeInvisibleDurationHook; + } + + public void setChangeInvisibleDurationHook( + ResponseHook changeInvisibleDurationHook) { + this.changeInvisibleDurationHook = changeInvisibleDurationHook; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 6df2e87db6..996e58a89c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -16,14 +16,21 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.ConsumerData; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.NoopCommand; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v2.ClientOverwrittenSettings; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Direction; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; +import io.grpc.stub.StreamObserver; import java.time.Duration; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; @@ -34,12 +41,17 @@ import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; import org.apache.rocketmq.proxy.common.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,11 +63,13 @@ public class ForwardClientService extends BaseService { private final ConsumerManager consumerManager; private final ProducerManager producerManager; private final PollResponseManager pollCommandResponseManager; + private final GrpcClientManager grpcClientManager; public ForwardClientService( ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager, + GrpcClientManager grpcClientManager, PollResponseManager pollCommandResponseManager ) { super(connectorManager); @@ -65,6 +79,7 @@ public class ForwardClientService extends BaseService { Duration.ofSeconds(10).toMillis(), TimeUnit.MILLISECONDS); this.channelManager = channelManager; + this.grpcClientManager = grpcClientManager; this.pollCommandResponseManager = pollCommandResponseManager; this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { @@ -80,90 +95,150 @@ public class ForwardClientService extends BaseService { this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); } - public void heartbeat(Context ctx, HeartbeatRequest request) { - String language = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE); - LanguageCode languageCode = LanguageCode.valueOf(language); - String clientId = request.getClientId(); + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + CompletableFuture future = new CompletableFuture<>(); - if (request.hasProducerData()) { - String producerGroup = GrpcConverter.wrapResourceWithNamespace(request.getProducerData().getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, producerGroup, clientId, pollCommandResponseManager); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - producerManager.registerProducer(producerGroup, clientChannelInfo); - } + try { + String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + LanguageCode languageCode = LanguageCode.valueOf(language); - if (request.hasConsumerData()) { - ConsumerData consumerData = request.getConsumerData(); - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(consumerData.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, pollCommandResponseManager); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - - consumerManager.registerConsumer( - consumerGroup, - clientChannelInfo, - GrpcConverter.buildConsumeType(consumerData.getConsumeType()), - GrpcConverter.buildMessageModel(consumerData.getConsumeModel()), - GrpcConverter.buildConsumeFromWhere(consumerData.getConsumePolicy()), - GrpcConverter.buildSubscriptionDataSet(consumerData.getSubscriptionsList()), - false - ); - } - } - - public void unregister(Context ctx, NotifyClientTerminationRequest request) { - String clientId = request.getClientId(); - - if (request.hasProducerGroup()) { - String producerGroup = GrpcConverter.wrapResourceWithNamespace(request.getProducerGroup()); - GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, producerGroup, clientId); - if (channel != null) { - producerManager.doChannelCloseEvent(producerGroup, channel); - } - } - - if (request.hasConsumerGroup()) { - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getConsumerGroup()); - GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); - if (channel != null) { - consumerManager.doChannelCloseEvent(consumerGroup, channel); - } - } - } - - public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - CompletableFuture future = new CompletableFuture<>(); - PollCommandResponse noopCommandResponse = PollCommandResponse.newBuilder().setNoopCommand( - NoopCommand.newBuilder().build() - ).build(); - - String clientId = request.getClientId(); - switch (request.getGroupCase()) { - case PRODUCER_GROUP: - Resource producerGroup = request.getProducerGroup(); - String producerGroupName = GrpcConverter.wrapResourceWithNamespace(producerGroup); - GrpcClientChannel producerChannel = GrpcClientChannel.getChannel(this.channelManager, producerGroupName, clientId); - if (producerChannel == null) { - future.complete(noopCommandResponse); - } else { - producerChannel.setClientObserver(future); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + switch (clientSettings.getClientType()) { + case PRODUCER: { + for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + // use topic name as producer group + producerManager.registerProducer(topicName, clientChannelInfo); + } + break; } - break; - case CONSUMER_GROUP: - Resource consumerGroup = request.getConsumerGroup(); - String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); - GrpcClientChannel consumerChannel = GrpcClientChannel.getChannel(this.channelManager, consumerGroupName, clientId); - if (consumerChannel == null) { - future.complete(noopCommandResponse); - } else { - consumerChannel.setClientObserver(future); + case PULL_CONSUMER: + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: { + if (!request.hasGroup()) { + throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); + } + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, pollCommandResponseManager); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + + consumerManager.registerConsumer( + consumerGroup, + clientChannelInfo, + GrpcConverter.buildConsumeType(clientSettings.getClientType()), + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + GrpcConverter.buildSubscriptionDataSet(clientSettings.getSettings() + .getSubscription() + .getSubscriptionsList()), + false + ); + break; } - break; - default: - break; + default: { + throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); + } + } + future.complete(HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + return future; + } catch (Throwable t) { + future.completeExceptionally(t); } return future; } + public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { + CompletableFuture future = new CompletableFuture<>(); + + try { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + + switch (clientSettings.getClientType()) { + case PRODUCER: + for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + // user topic name as producer group + GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); + if (channel != null) { + producerManager.doChannelCloseEvent(topicName, channel); + } + } + break; + case PULL_CONSUMER: + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: + if (!request.hasGroup()) { + throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); + } + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); + if (channel != null) { + consumerManager.doChannelCloseEvent(consumerGroup, channel); + } + break; + default: + break; + } + future.complete(NotifyClientTerminationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + return new StreamObserver() { + @Override + public void onNext(TelemetryCommand request) { + if (request.getCommandCase() == TelemetryCommand.CommandCase.CLIENT_SETTINGS) { + ClientSettings clientSettings = request.getClientSettings(); + grpcClientManager.updateClientSettings(clientId, clientSettings); + Settings settings = clientSettings.getSettings(); + if (settings.hasPublishing()) { + Publishing publishing = settings.getPublishing(); + for (Resource topic : publishing.getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + producerChannel.setClientObserver(responseObserver); + } + } + if (settings.hasSubscription()) { + Subscription subscription = settings.getSubscription(); + String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); + GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); + consumerChannel.setClientObserver(responseObserver); + } + responseObserver.onNext(TelemetryCommand.newBuilder() + .setClientOverwrittenSettings(ClientOverwrittenSettings.newBuilder() + .setNonce(clientSettings.getNonce()) + .setDirection(Direction.RESPONSE) + .setSettings(settings) + .build()) + .build()); + } + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + }; + } + private void scanNotActiveChannel() { try { this.consumerManager.scanNotActiveChannel(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index 4ea9ccd179..88bd809660 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -37,7 +37,7 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index fee3efce17..c2d9fdedea 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -68,7 +68,7 @@ public class ForwardClientServiceTest extends BaseServiceTest { assertNotNull(channel); assertTrue(channel instanceof GrpcClientChannel); - clientService.unregister(ctx, NotifyClientTerminationRequest.newBuilder() + clientService.notifyClientTermination(ctx, NotifyClientTerminationRequest.newBuilder() .setClientId("clientId") .setProducerGroup(Resource.newBuilder() .setName("producerGroup") @@ -127,7 +127,7 @@ public class ForwardClientServiceTest extends BaseServiceTest { assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); - clientService.unregister(ctx, NotifyClientTerminationRequest.newBuilder() + clientService.notifyClientTermination(ctx, NotifyClientTerminationRequest.newBuilder() .setClientId("clientId") .setConsumerGroup(Resource.newBuilder() .setName("consumerGroup") From 74cac24c67670ee348a4692bb755ad36fa52765f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 11 Apr 2022 19:04:26 +0800 Subject: [PATCH 094/338] [ISSUE #3949] v2 test cases --- .../v2/service/cluster/BaseServiceTest.java | 23 ++++ .../service/cluster/ConsumerServiceTest.java | 59 ++++++--- .../cluster/DefaultReadQueueSelectorTest.java | 7 +- .../DefaultWriteQueueSelectorTest.java | 67 ++++------ .../cluster/ForwardClientServiceTest.java | 124 ++++++++---------- .../service/cluster/ProducerServiceTest.java | 41 ++++-- .../cluster/PullMessageServiceTest.java | 40 +++--- .../v2/service/cluster/RouteServiceTest.java | 65 ++++++--- .../cluster/TransactionServiceTest.java | 20 ++- 9 files changed, 244 insertions(+), 202 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java index f7d0e9a98d..347a340ae0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java @@ -16,6 +16,8 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +import io.grpc.Context; +import io.grpc.Metadata; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.concurrent.ThreadLocalRandom; @@ -32,6 +34,8 @@ import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.junit.Before; import org.junit.Ignore; @@ -59,6 +63,13 @@ public abstract class BaseServiceTest extends InitConfigAndLoggerTest { protected TopicRouteCache topicRouteCache; @Mock protected TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; + @Mock + protected GrpcClientManager grpcClientManager; + + public static final String REMOTE_ADDRESS = "1.1.1.1"; + public static final String LOCAL_ADDRESS = "0.0.0.0"; + public static final String LANGUAGE = "JAVA"; + public static final String CLIENT_ID = "client-id"; @Before public void before() throws Throwable { @@ -70,6 +81,7 @@ public abstract class BaseServiceTest extends InitConfigAndLoggerTest { when(connectorManager.getTopicRouteCache()).thenReturn(topicRouteCache); when(connectorManager.getTransactionHeartbeatRegisterService()).thenReturn(transactionHeartbeatRegisterService); + initContext(); beforeEach(); } @@ -106,4 +118,15 @@ public abstract class BaseServiceTest extends InitConfigAndLoggerTest { MessageAccessor.putProperty(msg, MessageConst.PROPERTY_POP_CK, handler); return msg; } + + protected static Context initContext() { + Context ctx = Context.current(); + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDRESS); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDRESS); + metadata.put(InterceptorConstants.LANGUAGE, LANGUAGE); + metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); + ctx.withValue(InterceptorConstants.METADATA, metadata).attach(); + return ctx; + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 0a8c76a3a5..ccfb2a0fa0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -1,16 +1,19 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.FilterExpression; -import apache.rocketmq.v1.FilterType; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.Resource; -import com.google.rpc.Code; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.DeadLetterPolicy; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -49,7 +52,7 @@ public class ConsumerServiceTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { - consumerService = new ConsumerService(this.connectorManager); + consumerService = new ConsumerService(this.connectorManager, this.grpcClientManager); consumerService.setReadQueueSelector(readQueueSelector); } @@ -75,7 +78,7 @@ public class ConsumerServiceTest extends BaseServiceTest { consumerService.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); ReceiveMessageResponse response = consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") @@ -88,9 +91,9 @@ public class ConsumerServiceTest extends BaseServiceTest { .build() ).get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(1, response.getMessagesCount()); - assertEquals("msg1", response.getMessages(0).getSystemAttribute().getMessageId()); + assertEquals("msg1", response.getMessages(0).getSystemProperties().getMessageId()); assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); } @@ -112,7 +115,7 @@ public class ConsumerServiceTest extends BaseServiceTest { .build()) .get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); } @Test @@ -125,6 +128,9 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(producerClient).sendMessageBack(anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + ClientSettings clientSettings = createClientSettings(3); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") @@ -134,11 +140,10 @@ public class ConsumerServiceTest extends BaseServiceTest { .build()) .setReceiptHandle(receiptHandle.encode()) .setDeliveryAttempt(3) - .setMaxDeliveryAttempts(3) .build()) .get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(receiptHandle.getCommitLogOffset(), headerRef.get().getOffset().longValue()); } @@ -154,6 +159,9 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + ClientSettings clientSettings = createClientSettings(3); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") @@ -163,12 +171,23 @@ public class ConsumerServiceTest extends BaseServiceTest { .build()) .setReceiptHandle(receiptHandle.encode()) .setDeliveryAttempt(1) - .setMaxDeliveryAttempts(3) .build()) .get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(receiptHandle.getOffset(), headerRef.get().getOffset().longValue()); assertEquals(receiptHandle.encode(), headerRef.get().getExtraInfo()); } + + private ClientSettings createClientSettings(int maxDeliveryAttempts) { + return ClientSettings.newBuilder() + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() + .setMaxDeliveryAttempts(maxDeliveryAttempts) + .build()) + .build()) + .build()) + .build(); + } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java index 167ff99027..823b7437fd 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java @@ -1,8 +1,7 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.ReceiveMessageRequest; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; @@ -41,7 +40,7 @@ public class DefaultReadQueueSelectorTest extends BaseServiceTest { requestHeader.setTopic("readBrokerTopicByName"); SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), ReceiveMessageRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setBroker(Broker.newBuilder() .setName("brokerName") .build()) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java index c7aff6cd7f..b68d935530 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java @@ -1,18 +1,17 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SystemAttribute; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.ByteString; import io.grpc.Context; import java.nio.charset.StandardCharsets; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -23,6 +22,8 @@ import static org.mockito.Mockito.when; public class DefaultWriteQueueSelectorTest extends BaseServiceTest { + private static final String TOPIC_NAME = "namespace%topic"; + @Override public void beforeEach() throws Throwable { SelectableMessageQueue queue = new SelectableMessageQueue( @@ -44,40 +45,16 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .thenReturn(queue); } - @Test - public void testSendOrderMessageWithShardingKey() { - SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request), - GrpcConverter.buildMessage(request.getMessage())); - - assertEquals("selectOrderQueue", queue.getBrokerName()); - assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); - } - @Test public void selectWithShardingKey() { SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") .build()) - .putUserAttribute(MessageConst.PROPERTY_SHARDING_KEY, "key") - .setSystemAttribute(SystemAttribute.newBuilder() + .putUserProperties(MessageConst.PROPERTY_SHARDING_KEY, "key") + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) @@ -85,8 +62,8 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request), - GrpcConverter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), + GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -95,12 +72,12 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { @Test public void selectNormalQueue() { SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") .build()) - .setSystemAttribute(SystemAttribute.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) @@ -108,8 +85,8 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request), - GrpcConverter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), + GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); assertEquals("selectNormalQueue", queue.getBrokerName()); assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); @@ -118,17 +95,17 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { @Test public void selectTargetQueue() { SendMessageRequest request = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") .build()) - .setSystemAttribute(SystemAttribute.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) - .setPartition(Partition.newBuilder() + .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setBroker(Broker.newBuilder() .setName("brokerName") .build()) @@ -136,8 +113,8 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request), - GrpcConverter.buildMessage(request.getMessage())); + GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), + GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); assertEquals("selectTargetQueue", queue.getBrokerName()); assertEquals("selectTargetQueueAddr", queue.getBrokerAddr()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index c2d9fdedea..2c0aa30309 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -1,18 +1,17 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.ConsumeMessageType; -import apache.rocketmq.v1.ConsumeModel; -import apache.rocketmq.v1.ConsumePolicy; -import apache.rocketmq.v1.ConsumerData; -import apache.rocketmq.v1.FilterExpression; -import apache.rocketmq.v1.FilterType; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.ProducerData; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SubscriptionEntry; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import apache.rocketmq.v2.SubscriptionEntry; import io.grpc.Context; -import io.grpc.Metadata; import io.netty.channel.Channel; import java.util.ArrayList; import java.util.List; @@ -24,67 +23,63 @@ import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.PollResponseManager; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; public class ForwardClientServiceTest extends BaseServiceTest { private ChannelManager channelManager = new ChannelManager(); private PollResponseManager pollResponseManager = new PollResponseManager(); + private ForwardClientService clientService; @Override public void beforeEach() throws Throwable { - + clientService = new ForwardClientService( + this.connectorManager, + Executors.newSingleThreadScheduledExecutor(), + this.channelManager, + this.grpcClientManager, + this.pollResponseManager); } @Test public void testProducerHeartbeat() { - ForwardClientService clientService = new ForwardClientService( - this.connectorManager, - Executors.newSingleThreadScheduledExecutor(), - this.channelManager, - this.pollResponseManager); - - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "127.0.0.1:8080"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "127.0.0.1:8081"); - Context ctx = Context.current().withValue(InterceptorConstants.METADATA, metadata); - clientService.heartbeat(ctx, HeartbeatRequest.newBuilder() - .setClientId("clientId") - .setProducerData(ProducerData.newBuilder() - .setGroup(Resource.newBuilder() - .setName("producerGroup") + ClientSettings clientSettings = ClientSettings.newBuilder() + .setClientType(ClientType.PRODUCER) + .setSettings(Settings.newBuilder() + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder() + .setName("topic1") + .build()) + .addTopics(Resource.newBuilder() + .setName("topic2") + .build()) .build()) .build()) - .build()); + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); - assertEquals(1, clientService.getProducerManager().getGroupChannelTable().size()); - Channel channel = clientService.getProducerManager().findChannel("clientId"); + clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); + + assertEquals(2, clientService.getProducerManager().getGroupChannelTable().size()); + Channel channel = clientService.getProducerManager().findChannel(CLIENT_ID); assertNotNull(channel); assertTrue(channel instanceof GrpcClientChannel); - clientService.notifyClientTermination(ctx, NotifyClientTerminationRequest.newBuilder() - .setClientId("clientId") - .setProducerGroup(Resource.newBuilder() - .setName("producerGroup") - .build()) - .build()); + clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder().build()); assertTrue(clientService.getProducerManager().getGroupChannelTable().isEmpty()); } @Test public void testConsumerHeartbeat() { - ForwardClientService clientService = new ForwardClientService( - this.connectorManager, - Executors.newSingleThreadScheduledExecutor(), - this.channelManager, - this.pollResponseManager); - List subscriptionEntryList = new ArrayList<>(); subscriptionEntryList.add(SubscriptionEntry.newBuilder() .setTopic(Resource.newBuilder() @@ -95,29 +90,27 @@ public class ForwardClientServiceTest extends BaseServiceTest { .setType(FilterType.TAG) .build()) .build()); - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "127.0.0.1:8080"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "127.0.0.1:8081"); - Context ctx = Context.current().withValue(InterceptorConstants.METADATA, metadata); - clientService.heartbeat(ctx, HeartbeatRequest.newBuilder() - .setClientId("clientId") - .setConsumerData(ConsumerData.newBuilder() - .setGroup(Resource.newBuilder() - .setName("consumerGroup") + ClientSettings clientSettings = ClientSettings.newBuilder() + .setClientType(ClientType.PUSH_CONSUMER) + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .addAllSubscriptions(subscriptionEntryList) .build()) - .setConsumeType(ConsumeMessageType.PASSIVE) - .setConsumeModel(ConsumeModel.CLUSTERING) - .setConsumePolicy(ConsumePolicy.RESUME) - .addAllSubscriptions(subscriptionEntryList) + .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName("consumerGroup") .build()) .build()); - ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", "clientId"); + ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", CLIENT_ID); assertNotNull(clientChannelInfo); assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); - assertEquals("clientId", clientChannelInfo.getClientId()); + assertEquals(CLIENT_ID, clientChannelInfo.getClientId()); assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); ConsumerGroupInfo consumerGroupInfo = clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup"); assertEquals(MessageModel.CLUSTERING, consumerGroupInfo.getMessageModel()); @@ -127,9 +120,8 @@ public class ForwardClientServiceTest extends BaseServiceTest { assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); - clientService.notifyClientTermination(ctx, NotifyClientTerminationRequest.newBuilder() - .setClientId("clientId") - .setConsumerGroup(Resource.newBuilder() + clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder() + .setGroup(Resource.newBuilder() .setName("consumerGroup") .build()) .build()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 944ecce038..1b4c15fd52 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -16,13 +16,14 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import apache.rocketmq.v1.SystemAttribute; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.ByteString; -import com.google.rpc.Code; import io.grpc.Context; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; @@ -31,7 +32,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v1.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -46,12 +47,12 @@ import static org.mockito.Mockito.when; public class ProducerServiceTest extends BaseServiceTest { private static final SendMessageRequest REQUEST = SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") .build()) - .setSystemAttribute(SystemAttribute.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) @@ -78,8 +79,8 @@ public class ProducerServiceTest extends BaseServiceTest { try { SendMessageResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); - assertEquals("msgId", response.getMessageId()); + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals("msgId", response.getReceipts(0).getMessageId()); } catch (Exception e) { assertNull(e); } @@ -92,12 +93,12 @@ public class ProducerServiceTest extends BaseServiceTest { producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> null); CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setResourceNamespace("namespace") .setName("topic") .build()) - .setSystemAttribute(SystemAttribute.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) @@ -111,7 +112,7 @@ public class ProducerServiceTest extends BaseServiceTest { assertNotNull(e); assertTrue(e instanceof ExecutionException); assertTrue(e.getCause() instanceof ProxyException); - assertEquals(Code.NOT_FOUND, ((ProxyException) e.getCause()).getCode()); + assertEquals(Code.FORBIDDEN, ((ProxyException) e.getCause()).getCode()); } } @@ -163,4 +164,16 @@ public class ProducerServiceTest extends BaseServiceTest { assertSame(ex, e.getCause()); } } + +// @Test +// public void testForwardMessageToDeadLetterQueue() throws Exception { +// ProducerService producerService = new ProducerService(this.connectorManager); +// +// when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); +// producerService.forwardMessageToDeadLetterQueue(Context.current(), ForwardMessageToDeadLetterQueueRequest.newBuilder() +// .setMessageId("msgId") +// .setReceiptHandle(createReceiptHandle().encode()) +// .set +// .build()); +// } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java index b5cee9bbb9..23060b1b86 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java @@ -1,17 +1,17 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.Broker; -import apache.rocketmq.v1.FilterExpression; -import apache.rocketmq.v1.FilterType; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryOffsetPolicy; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.Resource; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryOffsetPolicy; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; +import apache.rocketmq.v2.Resource; import com.google.protobuf.util.Timestamps; -import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -49,7 +49,7 @@ public class PullMessageServiceTest extends BaseServiceTest { when(defaultClient.searchOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(CompletableFuture.completedFuture(50L)); QueryOffsetResponse response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) @@ -58,11 +58,11 @@ public class PullMessageServiceTest extends BaseServiceTest { .setPolicy(QueryOffsetPolicy.BEGINNING) .build() ).get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(0, response.getOffset()); response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) @@ -71,11 +71,11 @@ public class PullMessageServiceTest extends BaseServiceTest { .setPolicy(QueryOffsetPolicy.END) .build() ).get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(100, response.getOffset()); response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) @@ -85,7 +85,7 @@ public class PullMessageServiceTest extends BaseServiceTest { .setPolicy(QueryOffsetPolicy.TIME_POINT) .build() ).get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(50, response.getOffset()); } @@ -109,7 +109,7 @@ public class PullMessageServiceTest extends BaseServiceTest { Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); PullMessageResponse response = pullMessageService.pullMessage(ctx, PullMessageRequest.newBuilder() - .setPartition(Partition.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() .setBroker(Broker.newBuilder() .setName("brokerName") .build()) @@ -124,8 +124,8 @@ public class PullMessageServiceTest extends BaseServiceTest { .build()) .get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(1, response.getMessagesCount()); - assertEquals("msg1", response.getMessages(0).getSystemAttribute().getMessageId()); + assertEquals("msg1", response.getMessages(0).getSystemProperties().getMessageId()); } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 395f30b0c7..be88441fa3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -20,6 +20,7 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.MessageQueue; @@ -40,13 +41,14 @@ import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; public class RouteServiceTest extends BaseServiceTest { @@ -146,15 +148,20 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testLocalModeQueryRoute() throws Exception { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager); - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); + + ClientSettings clientSettings = ClientSettings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() .addAddresses(Address.newBuilder() .setPort(80) .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) @@ -168,8 +175,9 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryRouteWithInvalidEndpoints() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(ClientSettings.getDefaultInstance()); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") @@ -182,16 +190,20 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryRoute() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() + ClientSettings clientSettings = ClientSettings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() .addAddresses(Address.newBuilder() .setPort(80) .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) @@ -206,16 +218,20 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryRouteWhenTopicNotExist() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() + ClientSettings clientSettings = ClientSettings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() .addAddresses(Address.newBuilder() .setPort(80) .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("notExistTopic") .build()) @@ -227,8 +243,9 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryAssignmentInvalidEndpoints() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(ClientSettings.getDefaultInstance()); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic( Resource.newBuilder() @@ -243,23 +260,26 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testLocalModeQueryAssignment() throws Exception { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() + ClientSettings clientSettings = ClientSettings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() .addAddresses(Address.newBuilder() .setPort(80) .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) .setGroup(Resource.newBuilder() .setName("group") .build()) - .setClientId("clientId") .build()); QueryAssignmentResponse response = future.get(); @@ -271,23 +291,26 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryAssignment() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager); + RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setEndpoints(Endpoints.newBuilder() + ClientSettings clientSettings = ClientSettings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() .addAddresses(Address.newBuilder() .setPort(80) .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) .build()) + .build(); + when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") .build()) .setGroup(Resource.newBuilder() .setName("group") .build()) - .setClientId("clientId") .build()); QueryAssignmentResponse response = future.get(); @@ -297,4 +320,4 @@ public class RouteServiceTest extends BaseServiceTest { assertEquals("host", response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); } -} +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index cb108e7e83..5909ffac16 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -1,17 +1,16 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.Resource; -import com.google.rpc.Code; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.assertj.core.util.Lists; import org.junit.Test; @@ -60,8 +59,8 @@ public class TransactionServiceTest extends BaseServiceTest { createMessageExt("msgId", "msgId") )); - assertTrue(writeDataRef.get() instanceof PollCommandResponse); - PollCommandResponse response = (PollCommandResponse) writeDataRef.get(); + assertTrue(writeDataRef.get() instanceof TelemetryCommand); + TelemetryCommand response = (TelemetryCommand) writeDataRef.get(); assertEquals(transactionId.getProxyTransactionId(), response.getRecoverOrphanedTransactionCommand().getTransactionId()); } @@ -79,14 +78,11 @@ public class TransactionServiceTest extends BaseServiceTest { }).when(producerClient).endTransaction(anyString(), any()); EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) .setTransactionId(transactionId.getProxyTransactionId()) .build() ).get(); - assertEquals(Code.OK.getNumber(), response.getCommon().getStatus().getCode()); + assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(transactionId.getBrokerTransactionId(), headerRef.get().getTransactionId()); assertEquals("127.0.0.1:8080", brokerAddrRef.get()); } From 1060caec535b2d77f4ee9a4e7f0eca3aaec2072e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 11 Apr 2022 18:57:03 +0800 Subject: [PATCH 095/338] [ISSUE #3949] Refector telemetry command * Add unit test * Rename variable --- ...ager.java => TelemetryCommandManager.java} | 16 +++--- ...uture.java => TelemetryCommandRecord.java} | 16 +++--- .../v1/adapter/channel/GrpcClientChannel.java | 14 +++--- .../v2/adapter/channel/GrpcClientChannel.java | 12 ++--- .../grpc/v2/service/ClusterGrpcService.java | 6 +-- .../grpc/v2/service/LocalGrpcService.java | 50 ++++++++++++------- .../service/cluster/ForwardClientService.java | 16 +++--- .../grpc/v2/service/LocalGrpcServiceTest.java | 43 +++++++++++++++- .../cluster/ForwardClientServiceTest.java | 6 +-- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 1 - 10 files changed, 116 insertions(+), 64 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/common/{PollResponseManager.java => TelemetryCommandManager.java} (69%) rename proxy/src/main/java/org/apache/rocketmq/proxy/common/{PollResponseFuture.java => TelemetryCommandRecord.java} (76%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java similarity index 69% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java index a6dfd335e3..62c9be63d1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java @@ -21,17 +21,17 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; -public class PollResponseManager { - private final ConcurrentMap futureTable = new ConcurrentHashMap<>(); +public class TelemetryCommandManager { + private final ConcurrentMap commandTable = new ConcurrentHashMap<>(); private final AtomicLong commandIdGenerator = new AtomicLong(0); - public String putResponse(int opaque) { - String commandId = String.valueOf(commandIdGenerator.incrementAndGet()); - futureTable.put(commandId, new PollResponseFuture(commandId, opaque)); - return commandId; + public String putCommand(int opaque) { + String nonce = String.valueOf(commandIdGenerator.incrementAndGet()); + commandTable.put(nonce, new TelemetryCommandRecord(nonce, opaque)); + return nonce; } - public PollResponseFuture getResponse(String commandId) { - return futureTable.get(commandId); + public TelemetryCommandRecord getCommand(String commandId) { + return commandTable.get(commandId); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java similarity index 76% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java index fdf68b2117..adc074113f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/PollResponseFuture.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java @@ -17,22 +17,22 @@ package org.apache.rocketmq.proxy.common; -public class PollResponseFuture { - private final String commandId; +public class TelemetryCommandRecord { + private final String nonce; private final Integer opaque; - public PollResponseFuture(String commandId, int opaque) { - this.commandId = commandId; + public TelemetryCommandRecord(String nonce, int opaque) { + this.nonce = nonce; this.opaque = opaque; } - public PollResponseFuture(String commandId) { - this.commandId = commandId; + public TelemetryCommandRecord(String nonce) { + this.nonce = nonce; this.opaque = null; } - public String getCommandId() { - return commandId; + public String getNonce() { + return nonce; } public Integer getOpaque() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java index 5f993ff2b5..99f9ec6601 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java @@ -32,7 +32,7 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { @@ -40,13 +40,13 @@ public class GrpcClientChannel extends SimpleChannel { private final String group; private final String clientId; - private final PollResponseManager manager; + private final TelemetryCommandManager manager; - private GrpcClientChannel(String group, String clientId, PollResponseManager manager) { + private GrpcClientChannel(String group, String clientId, TelemetryCommandManager manager) { this(Context.current(), group, clientId, manager); } - private GrpcClientChannel(Context ctx, String group, String clientId, PollResponseManager manager) { + private GrpcClientChannel(Context ctx, String group, String clientId, TelemetryCommandManager manager) { super(ChannelManager.createSimpleChannelDirectly(ctx)); this.group = group; this.clientId = clientId; @@ -61,7 +61,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollResponseManager manager + TelemetryCommandManager manager ) { return create(Context.current(), channelManager, group, clientId, manager); } @@ -71,7 +71,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollResponseManager manager + TelemetryCommandManager manager ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), @@ -135,7 +135,7 @@ public class GrpcClientChannel extends SimpleChannel { if (!requestHeader.isJstackEnable()) { break; } - String commandId = manager.putResponse(command.getOpaque()); + String commandId = manager.putCommand(command.getOpaque()); future.complete(PollCommandResponse.newBuilder() .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() .setCommandId(commandId) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 8a945ef7da..2bbf6b84db 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -32,7 +32,7 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { @@ -40,9 +40,9 @@ public class GrpcClientChannel extends SimpleChannel { private final String group; private final String clientId; - private final PollResponseManager manager; + private final TelemetryCommandManager manager; - private GrpcClientChannel(Context ctx, String group, String clientId, PollResponseManager manager) { + private GrpcClientChannel(Context ctx, String group, String clientId, TelemetryCommandManager manager) { super(ChannelManager.createSimpleChannelDirectly(ctx)); this.group = group; this.clientId = clientId; @@ -57,7 +57,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollResponseManager manager + TelemetryCommandManager manager ) { return create(Context.current(), channelManager, group, clientId, manager); } @@ -67,7 +67,7 @@ public class GrpcClientChannel extends SimpleChannel { ChannelManager channelManager, String group, String clientId, - PollResponseManager manager + TelemetryCommandManager manager ) { GrpcClientChannel channel = channelManager.createChannel( buildKey(group, clientId), @@ -131,7 +131,7 @@ public class GrpcClientChannel extends SimpleChannel { if (!requestHeader.isJstackEnable()) { break; } - String nonce = manager.putResponse(command.getOpaque()); + String nonce = manager.putCommand(command.getOpaque()); streamObserver.onNext(TelemetryCommand.newBuilder() .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() .setNonce(nonce) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index e8caea4203..e1081ddd02 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -57,7 +57,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; @@ -82,13 +82,13 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ForwardClientService clientService; private final PullMessageService pullMessageService; private final TransactionService transactionService; - private final PollResponseManager pollCommandResponseManager; + private final TelemetryCommandManager pollCommandResponseManager; private final GrpcClientManager grpcClientManager; public ClusterGrpcService() { this.channelManager = new ChannelManager(); this.grpcClientManager = new GrpcClientManager(); - this.pollCommandResponseManager = new PollResponseManager(); + this.pollCommandResponseManager = new TelemetryCommandManager(); this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.consumerService = new ConsumerService(connectorManager, grpcClientManager); this.producerService = new ProducerService(connectorManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 730ef5ea0f..7a4c964e40 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -94,8 +94,8 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.common.PollResponseFuture; -import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; @@ -121,17 +121,26 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; - private final PollResponseManager pollCommandResponseManager; + private final TelemetryCommandManager telemetryCommandManager; private final GrpcClientManager grpcClientManager; private final RouteService routeService; private final DelayPolicy delayPolicy; public LocalGrpcService(BrokerController brokerController) { + this(brokerController, new TelemetryCommandManager()); + } + + /** + * For unit test + * @param brokerController BrokerController works in local mode + * @param telemetryCommandManager Used to manage telemetry command + */ + LocalGrpcService(BrokerController brokerController, TelemetryCommandManager telemetryCommandManager) { this.brokerController = brokerController; this.channelManager = new ChannelManager(); // TransactionStateChecker is not used in Local mode. ConnectorManager connectorManager = new ConnectorManager(null); - this.pollCommandResponseManager = new PollResponseManager(); + this.telemetryCommandManager = telemetryCommandManager; this.grpcClientManager = new GrpcClientManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); @@ -164,7 +173,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo case PRODUCER: { for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); this.brokerController.getClientManageProcessor() @@ -180,7 +189,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo case PUSH_CONSUMER: case SIMPLE_CONSUMER: { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); RemotingCommand response = this.brokerController.getClientManageProcessor() @@ -421,24 +430,27 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public void reportThreadStackTrace(ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); - PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(nonce); + TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); if (pollCommandResponseFuture != null) { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); - remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(threadStack); - remotingCommand.setBody(runningInfo.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + Integer opaque = pollCommandResponseFuture.getOpaque(); + if (opaque != null) { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); + remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(threadStack); + remotingCommand.setBody(runningInfo.encode()); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + } } } } public void reportVerifyMessageResult(VerifyMessageResult request) { String nonce = request.getNonce(); - PollResponseFuture pollCommandResponseFuture = pollCommandResponseManager.getResponse(nonce); + TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); if (pollCommandResponseFuture != null) { Integer opaque = pollCommandResponseFuture.getOpaque(); if (opaque != null) { @@ -528,14 +540,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Publishing publishing = settings.getPublishing(); for (Resource topic : publishing.getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { Subscription subscription = settings.getSubscription(); String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); + GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); consumerChannel.setClientObserver(responseObserver); } responseObserver.onNext(TelemetryCommand.newBuilder() diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 996e58a89c..f38a95741e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -44,8 +44,8 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.PollResponseManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; @@ -62,15 +62,15 @@ public class ForwardClientService extends BaseService { private final ChannelManager channelManager; private final ConsumerManager consumerManager; private final ProducerManager producerManager; - private final PollResponseManager pollCommandResponseManager; private final GrpcClientManager grpcClientManager; + private final TelemetryCommandManager telemetryCommandManager; public ForwardClientService( ConnectorManager connectorManager, ScheduledExecutorService scheduledExecutorService, ChannelManager channelManager, GrpcClientManager grpcClientManager, - PollResponseManager pollCommandResponseManager + TelemetryCommandManager telemetryCommandManager ) { super(connectorManager); scheduledExecutorService.scheduleWithFixedDelay( @@ -80,7 +80,7 @@ public class ForwardClientService extends BaseService { TimeUnit.MILLISECONDS); this.channelManager = channelManager; this.grpcClientManager = grpcClientManager; - this.pollCommandResponseManager = pollCommandResponseManager; + this.telemetryCommandManager = telemetryCommandManager; this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { @Override @@ -108,7 +108,7 @@ public class ForwardClientService extends BaseService { case PRODUCER: { for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); // use topic name as producer group producerManager.registerProducer(topicName, clientChannelInfo); @@ -122,7 +122,7 @@ public class ForwardClientService extends BaseService { throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); } String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, pollCommandResponseManager); + GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, telemetryCommandManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); consumerManager.registerConsumer( @@ -207,14 +207,14 @@ public class ForwardClientService extends BaseService { Publishing publishing = settings.getPublishing(); for (Resource topic : publishing.getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, pollCommandResponseManager); + GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { Subscription subscription = settings.getSubscription(); String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, pollCommandResponseManager); + GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); consumerChannel.setClientObserver(responseObserver); } responseObserver.onNext(TelemetryCommand.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 9e2f51b79f..0bb5eff536 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -49,6 +49,8 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.ThreadStackTrace; +import apache.rocketmq.v2.VerifyMessageResult; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import io.grpc.Context; @@ -79,11 +81,15 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; +import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.store.MessageStore; import org.apache.rocketmq.store.config.MessageStoreConfig; @@ -109,6 +115,9 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Mock private BrokerController brokerControllerMock; + @Mock + private TelemetryCommandManager telemetryCommandManager; + private Metadata metadata; private StreamObserver streamObserver; @@ -121,7 +130,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(brokerControllerMock.getPullMessageProcessor()).thenReturn(pullMessageProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); Mockito.when(brokerControllerMock.getMessageStoreConfig()).thenReturn(new MessageStoreConfig()); - localGrpcService = new LocalGrpcService(brokerControllerMock); + localGrpcService = new LocalGrpcService(brokerControllerMock, telemetryCommandManager); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); @@ -485,7 +494,39 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testReportThreadStackTrace() throws Exception { + int opaque = 1; + String nonce = "123"; + NettyRemotingServer remotingServerMock = Mockito.mock(NettyRemotingServer.class); + Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(remotingServerMock); + Mockito.doNothing().when(remotingServerMock).processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); + Mockito.when(telemetryCommandManager.getCommand(Mockito.eq(nonce))).thenReturn(new TelemetryCommandRecord(nonce, opaque)); + String jstack = "jstack"; + streamObserver.onNext(TelemetryCommand.newBuilder() + .setThreadStackTrace(ThreadStackTrace.newBuilder() + .setNonce(nonce) + .setThreadStackTrace(jstack).build()) + .build()); + Mockito.verify(remotingServerMock, Mockito.times(1)) + .processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); + } + + @Test + public void testReportVerifyMessageResult() { + int opaque = 1; + String nonce = "123"; + NettyRemotingServer remotingServerMock = Mockito.mock(NettyRemotingServer.class); + Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(remotingServerMock); + Mockito.doNothing().when(remotingServerMock).processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); + Mockito.when(telemetryCommandManager.getCommand(Mockito.eq(nonce))).thenReturn(new TelemetryCommandRecord(nonce, opaque)); + + streamObserver.onNext(TelemetryCommand.newBuilder() + .setVerifyMessageResult(VerifyMessageResult.newBuilder() + .setNonce(nonce) + .setStatus(ResponseBuilder.buildStatus(Code.OK, "ok")).build()) + .build()); + Mockito.verify(remotingServerMock, Mockito.times(1)) + .processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index 2c0aa30309..32aacfb3d4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -22,7 +22,7 @@ import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.PollResponseManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; @@ -37,7 +37,7 @@ import static org.mockito.Mockito.when; public class ForwardClientServiceTest extends BaseServiceTest { private ChannelManager channelManager = new ChannelManager(); - private PollResponseManager pollResponseManager = new PollResponseManager(); + private TelemetryCommandManager telemetryCommandManager = new TelemetryCommandManager(); private ForwardClientService clientService; @Override @@ -47,7 +47,7 @@ public class ForwardClientServiceTest extends BaseServiceTest { Executors.newSingleThreadScheduledExecutor(), this.channelManager, this.grpcClientManager, - this.pollResponseManager); + this.telemetryCommandManager); } @Test diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 7760be6458..91dd0245b2 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -107,7 +107,6 @@ public class GrpcBaseTest extends BaseConf { .setTopic(Resource.newBuilder() .setName(topic) .build()) - .setEndpoints(endpoints) .build(); } From 7fd29b43d4476784927e67920f3952c2a7d1a648 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 12 Apr 2022 13:52:49 +0800 Subject: [PATCH 096/338] [ISSUE #3949] Do refactor some code for readability. --- .../rocketmq/proxy/HealthCheckServer.java | 10 +-- .../apache/rocketmq/proxy/ProxyStartup.java | 2 +- .../proxy/grpc/v2/adapter/RequestMapping.java | 64 ++++++++++--------- .../grpc/v2/service/ClusterGrpcService.java | 4 +- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java index d058dccb28..2a6985c611 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java @@ -23,9 +23,9 @@ import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.proxy.config.ConfigurationManager; +import java.time.Duration; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; public class HealthCheckServer implements StartAndShutdown { @@ -34,7 +34,8 @@ public class HealthCheckServer implements StartAndShutdown { @Override public void start() throws Exception { this.healthChecker = HttpServer.create( - new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0); + new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0 + ); this.healthChecker.createContext("/status", new HealthCheckHandler()); this.healthChecker.setExecutor(null); this.healthChecker.start(); @@ -43,7 +44,8 @@ public class HealthCheckServer implements StartAndShutdown { @Override public void shutdown() throws InterruptedException { this.healthChecker.stop(0); - Thread.sleep(TimeUnit.SECONDS.toMillis(ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds())); + long waitAfterStopHealthCheckInSeconds = ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds(); + Thread.sleep(Duration.ofSeconds(waitAfterStopHealthCheckInSeconds).toMillis()); } static class HealthCheckHandler implements HttpHandler { 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 accb214777..57239a7954 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -73,7 +73,7 @@ public class ProxyStartup { try { PROXY_START_AND_SHUTDOWN.shutdown(); } catch (Exception e) { - log.error("err when shutdown proxy", e); + log.error("err when shutdown rmq-proxy", e); } })); } catch (Exception e) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index 2a25ff8eb7..add450e5a1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -35,38 +35,40 @@ import java.util.Map; import org.apache.rocketmq.common.protocol.RequestCode; public class RequestMapping { - private final static Map REQUEST_MAP = new HashMap() {{ - // v2 - put(QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); - put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); - put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); - put(PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); - put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + private final static Map REQUEST_MAP = new HashMap() { + { + // v2 + put(QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); + put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); + put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); + put(PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); + put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - // v1 - put(apache.rocketmq.v1.QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(apache.rocketmq.v1.HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(apache.rocketmq.v1.HealthCheckRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(apache.rocketmq.v1.SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); - put(apache.rocketmq.v1.QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(apache.rocketmq.v1.ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(apache.rocketmq.v1.AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); - put(apache.rocketmq.v1.NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); - put(apache.rocketmq.v1.PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(apache.rocketmq.v1.NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); - put(apache.rocketmq.v1.ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - }}; + // v1 + put(apache.rocketmq.v1.QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(apache.rocketmq.v1.HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(apache.rocketmq.v1.HealthCheckRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(apache.rocketmq.v1.SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); + put(apache.rocketmq.v1.QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(apache.rocketmq.v1.ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(apache.rocketmq.v1.AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); + put(apache.rocketmq.v1.NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); + put(apache.rocketmq.v1.PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(apache.rocketmq.v1.NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); + put(apache.rocketmq.v1.ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + } + }; public static int map(String rpcFullName) { if (REQUEST_MAP.containsKey(rpcFullName)) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index e1081ddd02..b44d958a50 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -72,7 +72,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread")); + new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") + ); private final ChannelManager channelManager; private final ConnectorManager connectorManager; @@ -179,7 +180,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc @Override public void start() throws Exception { - } @Override From 5a58f2cb10ff42775b26b0f391a8e30117ce92a4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 12 Apr 2022 20:27:02 +0800 Subject: [PATCH 097/338] [ISSUE #3949] v2 test cases --- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 87 +++++++++++++++++-- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 91dd0245b2..35f44032d1 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -19,11 +19,14 @@ package org.apache.rocketmq.test.grpc.v2; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ClientOverwrittenSettings; +import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -32,10 +35,12 @@ import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SystemProperties; +import apache.rocketmq.v2.TelemetryCommand; import com.google.protobuf.ByteString; import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import io.grpc.Channel; +import io.grpc.Metadata; import io.grpc.ServerInterceptors; import io.grpc.ServerServiceDefinition; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; @@ -43,16 +48,22 @@ import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; +import io.grpc.stub.MetadataUtils; +import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; import io.netty.handler.ssl.ApplicationProtocolNames; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; import java.security.cert.CertificateException; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLException; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; @@ -65,9 +76,52 @@ public class GrpcBaseTest extends BaseConf { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + protected final Metadata header = new Metadata(); + private static final int defaultQueueNums = 8; - protected Channel setUpServer(MessagingServiceGrpc.MessagingServiceImplBase serverImpl, + public void setUp() throws Exception { + header.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); + } + + protected MessagingServiceGrpc.MessagingServiceStub createStub(Channel channel) { + MessagingServiceGrpc.MessagingServiceStub stub = MessagingServiceGrpc.newStub(channel); + return MetadataUtils.attachHeaders(stub, header); + } + + protected MessagingServiceGrpc.MessagingServiceBlockingStub createBlockingStub(Channel channel) { + MessagingServiceGrpc.MessagingServiceBlockingStub stub = MessagingServiceGrpc.newBlockingStub(channel); + return MetadataUtils.attachHeaders(stub, header); + } + + protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, ClientSettings clientSettings) { + CompletableFuture future = CompletableFuture.completedFuture(ClientOverwrittenSettings.getDefaultInstance()); + StreamObserver requestStreamObserver = stub.telemetry(new StreamObserver() { + @Override + public void onNext(TelemetryCommand value) { + TelemetryCommand.CommandCase commandCase = value.getCommandCase(); + if (TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS.equals(commandCase)) { + future.complete(value.getClientOverwrittenSettings()); + } + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onCompleted() { + + } + }); + requestStreamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(clientSettings) + .build()); + return future; + } + + protected void setUpServer(MessagingServiceGrpc.MessagingServiceImplBase serverImpl, int port, boolean enableInterceptor) throws IOException, CertificateException { SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(serverImpl); @@ -81,7 +135,9 @@ public class GrpcBaseTest extends BaseConf { .useTransportSecurity(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) .build() .start()); - // Create a client channel and register for automatic graceful shutdown. + } + + protected Channel createChannel(int port) throws SSLException { return grpcCleanup.register(NettyChannelBuilder.forAddress("127.0.0.1", port) .directExecutor() .sslContext(SslContextBuilder @@ -99,10 +155,6 @@ public class GrpcBaseTest extends BaseConf { } public QueryRouteRequest buildQueryRouteRequest(String topic) { - return buildQueryRouteRequest(topic, Endpoints.getDefaultInstance()); - } - - public QueryRouteRequest buildQueryRouteRequest(String topic, Endpoints endpoints) { return QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) @@ -112,7 +164,7 @@ public class GrpcBaseTest extends BaseConf { public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { return SendMessageRequest.newBuilder() - .setMessages(0, Message.newBuilder() + .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -158,6 +210,21 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public NackMessageRequest buildNackMessageRequest(String group, String topic, String messageId, String receiptHandle, + int deliveryAttempt) { + return NackMessageRequest.newBuilder() + .setDeliveryAttempt(deliveryAttempt) + .setMessageId(messageId) + .setReceiptHandle(receiptHandle) + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .build(); + } + public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); assertThat(response.getMessageQueuesList().size()).isEqualTo(brokerSize * defaultQueueNums); @@ -183,4 +250,8 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getStatus() .getCode()).isEqualTo(Code.OK); } + + public void assertNackMessageResponse(NackMessageResponse response) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + } } \ No newline at end of file From 58241f374a1e3f1582fbdc700a4439cda811cc2e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 12 Apr 2022 20:28:44 +0800 Subject: [PATCH 098/338] [ISSUE #3949] v2 test cases --- pom.xml | 2 +- test/pom.xml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9e0faf55e7..467138921c 100644 --- a/pom.xml +++ b/pom.xml @@ -667,7 +667,7 @@ com.google.protobuf protobuf-java-util - 3.17.2 + 3.19.4 diff --git a/test/pom.xml b/test/pom.xml index 516e8fa7a7..823d3f75f1 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -35,6 +35,12 @@ ${project.groupId} rocketmq-proto + 2.0.0-SNAPSHOT + compatible + + + com.google.protobuf + protobuf-java-util ${project.groupId} From 78862bcd6b3e33b8beee8f432a3c7d6ae75e7d43 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 12 Apr 2022 20:49:14 +0800 Subject: [PATCH 099/338] [ISSUE #3949] v2 test cases --- .../rocketmq/proxy/config/ProxyConfig.java | 2 +- .../proxy/grpc/v2/adapter/GrpcConverter.java | 20 +- .../grpc/v2/service/GrpcClientManager.java | 7 + .../grpc/v2/service/LocalGrpcService.java | 3 +- .../v2/service/cluster/ConsumerService.java | 7 +- .../grpc/v2/service/cluster/RouteService.java | 6 +- .../service/cluster/ConsumerServiceTest.java | 13 +- .../v2/service/cluster/RouteServiceTest.java | 16 +- .../apache/rocketmq/test/base/BaseConf.java | 11 + .../test/grpc/v2/ClusterGrpcTest.java | 235 ++++++++++++++++++ .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 3 - .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 8 +- 12 files changed, 289 insertions(+), 42 deletions(-) create mode 100644 test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java 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 1375abc3e7..5b39f5bccc 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 @@ -80,7 +80,7 @@ public class ProxyConfig { private int longPollingReserveTimeInMillis = 10000; - private int retryDelayLevelDelta = 3; + private int retryDelayLevelDelta = 2; private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; private boolean enableACL = false; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 5819ce6dcc..40256e3193 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -205,7 +205,7 @@ public class GrpcConverter { return requestHeader; } - public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { + public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime, boolean isFifo) { Resource group = request.getGroup(); String groupName = GrpcConverter.wrapResourceWithNamespace(group); MessageQueue messageQueue = request.getMessageQueue(); @@ -219,7 +219,7 @@ public class GrpcConverter { maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; } long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); - long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); + long bornTime = System.currentTimeMillis(); FilterExpression filterExpression = request.getFilterExpression(); String expression = filterExpression.getExpression(); @@ -236,7 +236,7 @@ public class GrpcConverter { requestHeader.setInitMode(ConsumeInitMode.MAX); requestHeader.setExpType(expressionType); requestHeader.setExp(expression); - requestHeader.setOrder(request.getFifo()); + requestHeader.setOrder(isFifo); return requestHeader; } @@ -602,13 +602,6 @@ public class GrpcConverter { systemPropertiesBuilder.setStoreHost(storeHost.toString()); } - // delay_level - // TODO: delete -// String delayLevel = messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL); -// if (delayLevel != null) { -// systemAttributeBuilder.setDelayLevel(Integer.parseInt(delayLevel)); -// } - // delivery_timestamp String deliverMsString; long deliverMs; @@ -645,13 +638,6 @@ public class GrpcConverter { // delivery_attempt systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); - // publisher_group - // TODO: delete -// String producerGroup = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); -// if (producerGroup != null) { -// systemAttributeBuilder.setProducerGroup(buildResource(producerGroup)); -// } - // trace context String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); if (traceContext != null) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index eb86c41cfc..e3705c8532 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -18,13 +18,20 @@ package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.ClientSettings; +import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); + public ClientSettings getClientSettings(Context ctx) { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + return CLIENT_SETTINGS_MAP.get(clientId); + } + public ClientSettings getClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.get(clientId); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 7a4c964e40..eaa92a396e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -252,7 +252,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); - PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime); + PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, + clientSettings.getSettings().getSubscription().getFifo()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index ac744b4b3c..303cc5c25b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -130,7 +130,8 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); + boolean isFifo = grpcClientManager.getClientSettings(ctx).getSettings().getSubscription().getFifo(); + return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), isFifo); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { @@ -254,11 +255,10 @@ public class ConsumerService extends BaseService { } }); try { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - Settings settings = grpcClientManager.getClientSettings(clientId).getSettings(); + Settings settings = grpcClientManager.getClientSettings(ctx).getSettings(); int maxDeliveryAttempts = settings.getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( @@ -280,6 +280,7 @@ public class ConsumerService extends BaseService { }); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); + System.out.println(requestHeader); CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); resultFuture .thenAccept(result -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 2b240eca41..8ebea5c10a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -114,8 +114,7 @@ public class RouteService extends BaseService { List messageQueueList = new ArrayList<>(); if (ProxyMode.isClusterMode(mode.name())) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() @@ -246,8 +245,7 @@ public class RouteService extends BaseService { } } if (ProxyMode.isClusterMode(mode)) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index ccfb2a0fa0..5efa590fba 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -62,6 +62,15 @@ public class ConsumerServiceTest extends BaseServiceTest { new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); + ClientSettings clientSettings = ClientSettings.newBuilder() + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setFifo(false) + .build()) + .build()) + .build(); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + List messageExtList = Lists.newArrayList( createMessageExt("msg1", "msg1"), createMessageExt("msg2", "msg2") @@ -129,7 +138,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); ClientSettings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -160,7 +169,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); ClientSettings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index be88441fa3..62ca554f38 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -48,7 +48,7 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; public class RouteServiceTest extends BaseServiceTest { @@ -159,7 +159,7 @@ public class RouteServiceTest extends BaseServiceTest { .setScheme(AddressScheme.DOMAIN_NAME) .build()) .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -177,7 +177,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryRouteWithInvalidEndpoints() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(ClientSettings.getDefaultInstance()); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(ClientSettings.getDefaultInstance()); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") @@ -201,7 +201,7 @@ public class RouteServiceTest extends BaseServiceTest { .setScheme(AddressScheme.DOMAIN_NAME) .build()) .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -229,7 +229,7 @@ public class RouteServiceTest extends BaseServiceTest { .setScheme(AddressScheme.DOMAIN_NAME) .build()) .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -245,7 +245,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryAssignmentInvalidEndpoints() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(ClientSettings.getDefaultInstance()); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(ClientSettings.getDefaultInstance()); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic( Resource.newBuilder() @@ -271,7 +271,7 @@ public class RouteServiceTest extends BaseServiceTest { .setScheme(AddressScheme.DOMAIN_NAME) .build()) .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -302,7 +302,7 @@ public class RouteServiceTest extends BaseServiceTest { .setScheme(AddressScheme.DOMAIN_NAME) .build()) .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java index 4e29c84c6b..f1d24d20bf 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java @@ -48,6 +48,7 @@ import org.apache.rocketmq.test.factory.ConsumerFactory; import org.apache.rocketmq.test.listener.AbstractListener; import org.apache.rocketmq.test.util.MQAdminTestUtils; import org.apache.rocketmq.test.util.MQRandomUtils; +import org.apache.rocketmq.test.util.RandomUtils; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.apache.rocketmq.tools.admin.MQAdminExt; import org.junit.Assert; @@ -140,11 +141,21 @@ public class BaseConf { return initTopicWithName(topic); } + public static String initTopicOnSampleTopicBroker(String sampleTopic) { + String topic = RandomUtils.getStringWithNumber(10); + return initTopicOnSampleTopicBroker(topic, sampleTopic); + } + public static String initTopicWithName(String topicName) { IntegrationTestBase.initTopic(topicName, nsAddr, clusterName, CQType.SimpleCQ); return topicName; } + public static String initTopicOnSampleTopicBroker(String topicName, String sampleTopic) { + IntegrationTestBase.initTopic(topicName, nsAddr, sampleTopic, CQType.SimpleCQ); + return topicName; + } + public static String initConsumerGroup() { String group = MQRandomUtils.getRandomConsumerGroup(); return initConsumerGroup(group); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java new file mode 100644 index 0000000000..3f1725c3d2 --- /dev/null +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -0,0 +1,235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.test.grpc.v2; + +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.ClientOverwrittenSettings; +import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.DeadLetterPolicy; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessagingServiceGrpc; +import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import io.grpc.Channel; +import java.net.URL; +import java.time.Duration; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.consumer.PullStatus; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; +import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; +import org.apache.rocketmq.test.util.MQAdminTestUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; +import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; +import static org.awaitility.Awaitility.await; + +public class ClusterGrpcTest extends GrpcBaseTest { + + private final int PORT = 8082; + private GrpcForwardService grpcForwardService; + private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + private MessagingServiceGrpc.MessagingServiceStub stub; + + @Before + public void setUp() throws Exception { + super.setUp(); + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); + ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + grpcForwardService = new ClusterGrpcService(); + grpcForwardService.start(); + GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); + setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); + stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); + + System.out.println(nsAddr); + await().atMost(Duration.ofSeconds(40)).until(() -> { + Map brokerDataMap = MQAdminTestUtils.getCluster(nsAddr).getBrokerAddrTable(); + return brokerDataMap.size() == brokerNum; + }); + System.out.println(MQAdminTestUtils.getCluster(nsAddr)); + } + + @After + public void tearDown() throws Exception { + grpcForwardService.shutdown(); + shutdown(); + } + + @Test + public void testQueryRoute() throws Exception { + String topic = initTopic(); + String requestId = UUID.randomUUID().toString(); + CompletableFuture future = this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(requestId) + .setAccessPoint(Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder() + .setHost("127.0.0.1") + .setPort(PORT) + .build()) + .build()) + .build()); +// System.out.println(future.get()); + +// TimeUnit.SECONDS.sleep(3); + QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); + assertQueryRoute(response, brokerControllerList.size()); + } + + @Test + public void testSendReceiveMessage() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PRODUCER) + .build()) + .get(); + + String group = "group"; + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PUSH_CONSUMER) + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setFifo(false) + .build()) + .build()) + .build()) + .get(); + + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + assertReceiveMessage(receiveResponse, messageId); + String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, receiptHandle)); + assertAck(ackMessageResponse); + } + + @Test + public void testSendReceiveMessageThenToDLQ() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PRODUCER) + .build()) + .get(); + + String group = "group"; + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PUSH_CONSUMER) + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() + .setMaxDeliveryAttempts(2) + .build()) + .setFifo(false) + .build()) + .build()) + .build()) + .get(); + + ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + assertReceiveMessage(receiveResponse, messageId); + + Message message = receiveResponse.getMessages(0); + NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( + group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 1 + )); + assertNackMessageResponse(nackMessageResponse); + + AtomicReference receiveRetryResponseRef = new AtomicReference<>(); + await().atMost(Duration.ofSeconds(60)).until(() -> { + ReceiveMessageResponse receiveRetryResponse = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + if (receiveRetryResponse.getMessagesCount() <= 0) { + return false; + } + receiveRetryResponseRef.set(receiveRetryResponse); + return receiveRetryResponse.getMessages(0).getSystemProperties() + .getMessageId().equals(messageId); + }); + + message = receiveRetryResponseRef.get().getMessages(0); + nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( + group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 2 + )); + assertNackMessageResponse(nackMessageResponse); + + DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); + defaultMQPullConsumer.start(); + MessageQueue dlqMQ = new MessageQueue(MixAll.getDLQTopic(group), topic, 0); + await().atMost(Duration.ofSeconds(10)).until(() -> { + try { + PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); + if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { + return false; + } + MessageExt messageExt = pullResult.getMsgFoundList().get(0); + return messageId.equals(messageExt.getMsgId()); + } catch (Throwable ignore) { + return false; + } + }); + + System.out.println(1); + } + + +} diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 35f44032d1..f94c41c3f3 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -192,9 +192,6 @@ public class GrpcBaseTest extends BaseConf { .setInvisibleDuration(Duration.newBuilder() .setSeconds(3) .build()) - .setInitializationTimestamp(Timestamp.newBuilder() - .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) - .build()) .build(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index 3b2610848e..30c7c50270 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -22,7 +22,6 @@ import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.SendMessageResponse; -import io.grpc.Channel; import java.net.URL; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -37,10 +36,12 @@ import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HO public class LocalGrpcTest extends GrpcBaseTest { private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + private MessagingServiceGrpc.MessagingServiceStub stub; private LocalGrpcService localGrpcService; @Before public void setUp() throws Exception { + super.setUp(); String mockProxyHome = "/mock/rmq/proxy/home"; URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); if (mockProxyHomeURL != null) { @@ -54,8 +55,9 @@ public class LocalGrpcTest extends GrpcBaseTest { localGrpcService = new LocalGrpcService(brokerController1); localGrpcService.start(); GrpcMessagingProcessor processor = new GrpcMessagingProcessor(localGrpcService); - Channel channel = setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); - blockingStub = MessagingServiceGrpc.newBlockingStub(channel); + setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); + stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); } @After From 2a240b7fc250a4d205ba942e3a5d564baef7bf4f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 13 Apr 2022 11:58:16 +0800 Subject: [PATCH 100/338] [ISSUE #3949] Add super.onMessage in AuthenticationInterceptor --- .../proxy/grpc/interceptor/AuthenticationInterceptor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index e79453f9b7..b73c5cb085 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -58,6 +58,7 @@ public class AuthenticationInterceptor implements ServerInterceptor { for (AccessValidator accessValidator : accessValidatorList) { accessValidator.validate(accessValidator.parse(messageV3, metadataHeader)); } + super.onMessage(message); } }; } From 41a976693c72803c174d14a8fe98420d5f528395 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 13 Apr 2022 18:56:42 +0800 Subject: [PATCH 101/338] [ISSUE #3949] v2 test cases --- .../ChangeInvisibleTimeProcessor.java | 1 + .../rocketmq/proxy/config/ProxyConfig.java | 6 +- .../connector/client/MQClientAPIExt.java | 15 + .../proxy/grpc/v2/adapter/GrpcConverter.java | 14 + .../v2/service/cluster/ConsumerService.java | 14 +- .../service/cluster/ForwardClientService.java | 2 + .../service/cluster/PullMessageService.java | 8 +- .../apache/rocketmq/test/base/BaseConf.java | 2 +- .../test/grpc/v2/ClusterGrpcTest.java | 172 +------ .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 433 +++++++++++++++++- .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 44 +- 11 files changed, 481 insertions(+), 230 deletions(-) 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 991a7058d9..5ab1647e45 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 @@ -179,6 +179,7 @@ public class ChangeInvisibleTimeProcessor implements NettyRequestProcessor { ck.setTopic(requestHeader.getTopic()); ck.setQueueId((byte) queueId); ck.addDiff(0); + ck.setBrokerName(brokerName); msgInner.setBody(JSON.toJSONString(ck).getBytes(DataConverter.charset)); msgInner.setQueueId(reviveQid); 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 5b39f5bccc..cddce40d0b 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 @@ -78,7 +78,7 @@ public class ProxyConfig { private int transactionHeartbeatPeriodSecond = 20; private int transactionHeartbeatBatchNum = 100; - private int longPollingReserveTimeInMillis = 10000; + private long longPollingReserveTimeInMillis = 10000; private int retryDelayLevelDelta = 2; private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; @@ -373,11 +373,11 @@ public class ProxyConfig { this.transactionHeartbeatBatchNum = transactionHeartbeatBatchNum; } - public int getLongPollingReserveTimeInMillis() { + public long getLongPollingReserveTimeInMillis() { return longPollingReserveTimeInMillis; } - public void setLongPollingReserveTimeInMillis(int longPollingReserveTimeInMillis) { + public void setLongPollingReserveTimeInMillis(long longPollingReserveTimeInMillis) { this.longPollingReserveTimeInMillis = longPollingReserveTimeInMillis; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java index 4859587348..b2d9cf9330 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector.client; +import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -26,15 +27,19 @@ import org.apache.rocketmq.client.consumer.PopCallback; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PullCallback; 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.impl.ClientRemotingProcessor; import org.apache.rocketmq.client.impl.CommunicationMode; import org.apache.rocketmq.client.impl.MQClientAPIImpl; +import org.apache.rocketmq.client.impl.consumer.PullResultExt; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; @@ -299,6 +304,16 @@ public class MQClientAPIExt extends MQClientAPIImpl { new PullCallback() { @Override public void onSuccess(PullResult pullResult) { + PullResultExt pullResultExt = (PullResultExt) pullResult; + if (PullStatus.FOUND.equals(pullResult.getPullStatus())) { + List messageExtList = MessageDecoder.decodesBatch( + ByteBuffer.wrap(pullResultExt.getMessageBinary()), + true, + false, + true + ); + pullResult.setMsgFoundList(messageExtList); + } future.complete(pullResult); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 40256e3193..a67844a85a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -255,6 +255,20 @@ public class GrpcConverter { return ackMessageRequestHeader; } + public static AckMessageRequestHeader buildAckMessageRequestHeader(NackMessageRequest request) { + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + ackMessageRequestHeader.setConsumerGroup(groupName); + ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + return ackMessageRequestHeader; + } + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, DelayPolicy delayPolicy) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 303cc5c25b..1c80d715c5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -37,11 +37,13 @@ import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -49,8 +51,6 @@ import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.common.DelayPolicy; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; @@ -270,6 +270,11 @@ public class ConsumerService extends BaseService { .thenAccept(result -> { try { future.complete(convertToNackMessageResponse(ctx, request, result)); + if (result.getCode() == ResponseCode.SUCCESS) { + writeConsumer.ackMessage( + brokerAddr, + this.buildAckMessageRequestHeader(ctx, request)); + } } catch (Throwable throwable) { future.completeExceptionally(throwable); } @@ -280,7 +285,6 @@ public class ConsumerService extends BaseService { }); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); - System.out.println(requestHeader); CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); resultFuture .thenAccept(result -> { @@ -305,6 +309,10 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } + protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, NackMessageRequest request) { + return GrpcConverter.buildAckMessageRequestHeader(request); + } + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request, int maxReconsumeTimes) { return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index f38a95741e..770294eefb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -207,6 +207,8 @@ public class ForwardClientService extends BaseService { Publishing publishing = settings.getPublishing(); for (Resource topic : publishing.getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + // use topic name as producer group + connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); producerChannel.setClientObserver(responseObserver); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java index 1a07415e95..91194ffb66 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java @@ -62,10 +62,10 @@ public class PullMessageService extends BaseService { }); try { - MessageQueue partition = request.getMessageQueue(); - String topic = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); - String brokerName = partition.getBroker().getName(); - int queueId = partition.getId(); + MessageQueue messageQueue = request.getMessageQueue(); + String topic = GrpcConverter.wrapResourceWithNamespace(messageQueue.getTopic()); + String brokerName = messageQueue.getBroker().getName(); + int queueId = messageQueue.getId(); CompletableFuture offsetFuture; switch (request.getPolicy()) { diff --git a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java index f1d24d20bf..058ad91919 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java @@ -142,7 +142,7 @@ public class BaseConf { } public static String initTopicOnSampleTopicBroker(String sampleTopic) { - String topic = RandomUtils.getStringWithNumber(10); + String topic = MQRandomUtils.getRandomTopic(); return initTopicOnSampleTopicBroker(topic, sampleTopic); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 3f1725c3d2..168d011795 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -17,36 +17,10 @@ package org.apache.rocketmq.test.grpc.v2; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.ClientOverwrittenSettings; -import apache.rocketmq.v2.ClientSettings; -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.DeadLetterPolicy; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.MessagingServiceGrpc; -import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; -import io.grpc.Channel; -import java.net.URL; import java.time.Duration; import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; -import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.consumer.PullStatus; -import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; @@ -57,43 +31,24 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; -import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; import static org.awaitility.Awaitility.await; public class ClusterGrpcTest extends GrpcBaseTest { - private final int PORT = 8082; private GrpcForwardService grpcForwardService; - private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; - private MessagingServiceGrpc.MessagingServiceStub stub; @Before public void setUp() throws Exception { super.setUp(); - String mockProxyHome = "/mock/rmq/proxy/home"; - URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); - if (mockProxyHomeURL != null) { - mockProxyHome = mockProxyHomeURL.toURI().getPath(); - } - System.setProperty(RMQ_PROXY_HOME, mockProxyHome); - ConfigurationManager.initEnv(); - ConfigurationManager.intConfig(); - ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); - ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); grpcForwardService = new ClusterGrpcService(); grpcForwardService.start(); GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); - blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); - stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); - System.out.println(nsAddr); await().atMost(Duration.ofSeconds(40)).until(() -> { Map brokerDataMap = MQAdminTestUtils.getCluster(nsAddr).getBrokerAddrTable(); return brokerDataMap.size() == brokerNum; }); - System.out.println(MQAdminTestUtils.getCluster(nsAddr)); } @After @@ -105,131 +60,20 @@ public class ClusterGrpcTest extends GrpcBaseTest { @Test public void testQueryRoute() throws Exception { String topic = initTopic(); - String requestId = UUID.randomUUID().toString(); - CompletableFuture future = this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(requestId) - .setAccessPoint(Endpoints.newBuilder() - .setScheme(AddressScheme.IPv4) - .addAddresses(Address.newBuilder() - .setHost("127.0.0.1") - .setPort(PORT) - .build()) - .build()) - .build()); -// System.out.println(future.get()); + this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); -// TimeUnit.SECONDS.sleep(3); QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); - assertQueryRoute(response, brokerControllerList.size()); + assertQueryRoute(response, brokerNum * defaultQueueNums); } @Test - public void testSendReceiveMessage() throws Exception { - String topic = initTopicOnSampleTopicBroker(broker1Name); - this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PRODUCER) - .build()) - .get(); - + public void testQueryAssignment() throws Exception { + String topic = initTopic(); String group = "group"; - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); - assertSendMessage(sendResponse, messageId); + this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); - this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PUSH_CONSUMER) - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setFifo(false) - .build()) - .build()) - .build()) - .get(); + QueryAssignmentResponse response = blockingStub.queryAssignment(buildQueryAssignmentRequest(topic, group)); - ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); - assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, receiptHandle)); - assertAck(ackMessageResponse); + assertQueryAssignment(response, brokerNum); } - - @Test - public void testSendReceiveMessageThenToDLQ() throws Exception { - String topic = initTopicOnSampleTopicBroker(broker1Name); - this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PRODUCER) - .build()) - .get(); - - String group = "group"; - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); - assertSendMessage(sendResponse, messageId); - - this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PUSH_CONSUMER) - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() - .setMaxDeliveryAttempts(2) - .build()) - .setFifo(false) - .build()) - .build()) - .build()) - .get(); - - ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); - assertReceiveMessage(receiveResponse, messageId); - - Message message = receiveResponse.getMessages(0); - NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 1 - )); - assertNackMessageResponse(nackMessageResponse); - - AtomicReference receiveRetryResponseRef = new AtomicReference<>(); - await().atMost(Duration.ofSeconds(60)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); - if (receiveRetryResponse.getMessagesCount() <= 0) { - return false; - } - receiveRetryResponseRef.set(receiveRetryResponse); - return receiveRetryResponse.getMessages(0).getSystemProperties() - .getMessageId().equals(messageId); - }); - - message = receiveRetryResponseRef.get().getMessages(0); - nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 2 - )); - assertNackMessageResponse(nackMessageResponse); - - DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); - defaultMQPullConsumer.start(); - MessageQueue dlqMQ = new MessageQueue(MixAll.getDLQTopic(group), topic, 0); - await().atMost(Duration.ofSeconds(10)).until(() -> { - try { - PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); - if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { - return false; - } - MessageExt messageExt = pullResult.getMsgFoundList().get(0); - return messageId.equals(messageExt.getMsgId()); - } catch (Throwable ignore) { - return false; - } - }); - - System.out.println(1); - } - - } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index f94c41c3f3..5bb2471cb7 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -19,26 +19,49 @@ package org.apache.rocketmq.test.grpc.v2; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Broker; import apache.rocketmq.v2.ClientOverwrittenSettings; import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.DeadLetterPolicy; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PullMessageResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryOffsetPolicy; +import apache.rocketmq.v2.QueryOffsetRequest; +import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.TransactionResolution; +import apache.rocketmq.v2.TransactionSource; import com.google.protobuf.ByteString; import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Timestamps; import io.grpc.Channel; import io.grpc.Metadata; import io.grpc.ServerInterceptors; @@ -55,33 +78,67 @@ import io.netty.handler.ssl.ApplicationProtocolNames; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; +import java.net.URL; import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import javax.net.ssl.SSLException; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.consumer.PullStatus; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; +import org.junit.Test; +import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; +import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; public class GrpcBaseTest extends BaseConf { + + protected final int PORT = 8082; /** * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. */ @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + protected MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; + protected MessagingServiceGrpc.MessagingServiceStub stub; protected final Metadata header = new Metadata(); - private static final int defaultQueueNums = 8; + protected static final int defaultQueueNums = 8; public void setUp() throws Exception { header.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); + + String mockProxyHome = "/mock/rmq/proxy/home"; + URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); + if (mockProxyHomeURL != null) { + mockProxyHome = mockProxyHomeURL.toURI().getPath(); + } + System.setProperty(RMQ_PROXY_HOME, mockProxyHome); + ConfigurationManager.initEnv(); + ConfigurationManager.intConfig(); + ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); + ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + + blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); + stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); } protected MessagingServiceGrpc.MessagingServiceStub createStub(Channel channel) { @@ -95,8 +152,8 @@ public class GrpcBaseTest extends BaseConf { } protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, ClientSettings clientSettings) { - CompletableFuture future = CompletableFuture.completedFuture(ClientOverwrittenSettings.getDefaultInstance()); - StreamObserver requestStreamObserver = stub.telemetry(new StreamObserver() { + CompletableFuture future = new CompletableFuture<>(); + StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { @Override public void onNext(TelemetryCommand value) { TelemetryCommand.CommandCase commandCase = value.getCommandCase(); @@ -104,20 +161,11 @@ public class GrpcBaseTest extends BaseConf { future.complete(value.getClientOverwrittenSettings()); } } - - @Override - public void onError(Throwable t) { - - } - - @Override - public void onCompleted() { - - } }); requestStreamObserver.onNext(TelemetryCommand.newBuilder() .setClientSettings(clientSettings) .build()); + requestStreamObserver.onCompleted(); return future; } @@ -154,6 +202,183 @@ public class GrpcBaseTest extends BaseConf { .build()); } + @Test + public void testSendReceiveMessage() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = "group"; + + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PRODUCER) + .build()) + .get(); + + // init consumer offset + receiveMessage(blockingStub, topic, group); + + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); + + ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group); + assertReceiveMessage(response, messageId); + String receiptHandle = response.getMessages(0).getSystemProperties().getReceiptHandle(); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, receiptHandle)); + assertAck(ackMessageResponse); + } + + @Test + public void testSendReceiveMessageThenToDLQ() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + this.sendClientSettings(stub, ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PRODUCER) + .build()) + .get(); + + String group = "group"; + + // init consumer offset + receiveMessage(blockingStub, topic, group); + + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); + + ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group); + assertReceiveMessage(receiveResponse, messageId); + + Message message = receiveResponse.getMessages(0); + NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( + group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 1 + )); + assertNackMessageResponse(nackMessageResponse); + + AtomicReference receiveRetryResponseRef = new AtomicReference<>(); + await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group); + if (receiveRetryResponse.getMessagesCount() <= 0) { + return false; + } + receiveRetryResponseRef.set(receiveRetryResponse); + return receiveRetryResponse.getMessages(0).getSystemProperties() + .getMessageId().equals(messageId); + }); + + message = receiveRetryResponseRef.get().getMessages(0); + nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( + group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 2 + )); + assertNackMessageResponse(nackMessageResponse); + + DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); + defaultMQPullConsumer.start(); + org.apache.rocketmq.common.message.MessageQueue dlqMQ = new org.apache.rocketmq.common.message.MessageQueue(MixAll.getDLQTopic(group), broker1Name, 0); + await().atMost(java.time.Duration.ofSeconds(10)).until(() -> { + try { + PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); + if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { + return false; + } + MessageExt messageExt = pullResult.getMsgFoundList().get(0); + return messageId.equals(messageExt.getMsgId()); + } catch (Throwable ignore) { + return false; + } + }); + } + + @Test + public void testTransactionCheckThenCommit() { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = "group"; + + AtomicReference telemetryCommandRef = new AtomicReference<>(null); + StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { + @Override + public void onNext(TelemetryCommand value) { + telemetryCommandRef.set(value); + } + }); + + try { + requestStreamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(buildProducerClientSettings(topic)) + .build()); + + // init consumer offset + receiveMessage(blockingStub, topic, group); + + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildTransactionSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + await().atMost(java.time.Duration.ofSeconds(60)).until(() -> { + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.RECOVER_ORPHANED_TRANSACTION_COMMAND) { + return false; + } + return telemetryCommandRef.get() != null; + }); + RecoverOrphanedTransactionCommand recoverOrphanedTransactionCommand = telemetryCommandRef.get().getRecoverOrphanedTransactionCommand(); + assertRecoverOrphanedTransactionCommand(recoverOrphanedTransactionCommand, messageId); + + EndTransactionResponse endTransactionResponse = blockingStub.endTransaction( + buildEndTransactionRequest(topic, messageId, recoverOrphanedTransactionCommand.getTransactionId(), TransactionResolution.COMMIT)); + assertEndTransactionResponse(endTransactionResponse); + + requestStreamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(buildPushConsumerClientSettings()) + .build()); + + await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group); + if (receiveRetryResponse.getMessagesCount() <= 0) { + return false; + } + return receiveRetryResponse.getMessages(0).getSystemProperties() + .getMessageId().equals(messageId); + }); + } finally { + requestStreamObserver.onCompleted(); + } + } + + @Test + public void testPullMessage() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = "group"; + String messageId = createUniqID(); + + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + assertSendMessage(blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)), messageId); + + this.sendClientSettings(stub, buildPullConsumerClientSettings()).get(); + + QueryOffsetResponse queryOffsetResponse = blockingStub.queryOffset(buildQueryOffsetRequest(broker1Name, topic, QueryOffsetPolicy.BEGINNING)); + assertQueryOffsetResponse(queryOffsetResponse, 0L); + + queryOffsetResponse = blockingStub.queryOffset(buildQueryOffsetRequest(broker1Name, topic, QueryOffsetPolicy.END)); + assertQueryOffsetResponse(queryOffsetResponse, 1L); + + await().atMost(java.time.Duration.ofSeconds(10)).until(() -> { + PullMessageResponse response = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) + .pullMessage(buildPullMessageRequest(broker1Name, group, topic, 0L)); + if (response.getMessagesCount() <= 0) { + return false; + } + return response.getMessages(0).getSystemProperties().getMessageId().equals(messageId); + }); + } + + public ReceiveMessageResponse receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { + return stub.withDeadlineAfter(15, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + } + public QueryRouteRequest buildQueryRouteRequest(String topic) { return QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -162,8 +387,20 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public QueryAssignmentRequest buildQueryAssignmentRequest(String topic, String group) { + return QueryAssignmentRequest.newBuilder() + .setTopic(Resource.newBuilder().setName(topic).build()) + .setGroup(Resource.newBuilder().setName(group).build()) + .build(); + } + public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { return SendMessageRequest.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .build()) .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) @@ -171,6 +408,33 @@ public class GrpcBaseTest extends BaseConf { .setSystemProperties(SystemProperties.newBuilder() .setMessageId(messageId) .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build(); + } + + public SendMessageRequest buildTransactionSendMessageRequest(String topic, String messageId) { + return SendMessageRequest.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .build()) + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(messageId) + .setQueueId(0) + .setMessageType(MessageType.TRANSACTION) + .setOrphanedTransactionRecoveryDuration(Duration.newBuilder().setSeconds(10)) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) .build()) .setBody(ByteString.copyFromUtf8("123")) .build()) @@ -222,12 +486,54 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { + public EndTransactionRequest buildEndTransactionRequest(String topic, String messageId, String transactionId, TransactionResolution resolution) { + return EndTransactionRequest.newBuilder() + .setMessageId(messageId) + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setTransactionId(transactionId) + .setResolution(resolution) + .setSource(TransactionSource.SOURCE_SERVER_CHECK) + .build(); + } + + public QueryOffsetRequest buildQueryOffsetRequest(String brokerName, String topic, QueryOffsetPolicy queryOffsetPolicy) { + return QueryOffsetRequest.newBuilder() + .setMessageQueue(MessageQueue.newBuilder() + .setTopic(Resource.newBuilder().setName(topic).build()) + .setBroker(Broker.newBuilder().setName(brokerName).build()) + .setId(0) + .build()) + .setPolicy(queryOffsetPolicy) + .build(); + } + + public PullMessageRequest buildPullMessageRequest(String brokerName, String group, String topic, long offset) { + return PullMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(group).build()) + .setMessageQueue(MessageQueue.newBuilder() + .setTopic(Resource.newBuilder().setName(topic).build()) + .setBroker(Broker.newBuilder().setName(brokerName).build()) + .setId(0) + .build()) + .setBatchSize(32) + .setOffset(offset) + .build(); + } + + public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(response.getMessageQueuesList().size()).isEqualTo(brokerSize * defaultQueueNums); + assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); assertThat(response.getMessageQueues(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } + public void assertQueryAssignment(QueryAssignmentResponse response, int assignmentCount) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getAssignmentsCount()).isEqualTo(assignmentCount); + assertThat(response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); + } + public void assertSendMessage(SendMessageResponse response, String messageId) { assertThat(response.getStatus() .getCode()).isEqualTo(Code.OK); @@ -251,4 +557,101 @@ public class GrpcBaseTest extends BaseConf { public void assertNackMessageResponse(NackMessageResponse response) { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); } + + public void assertRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand command, String messageId) { + assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) + .isEqualTo(messageId); + assertThat(command.getTransactionId()).isNotBlank(); + } + + public void assertEndTransactionResponse(EndTransactionResponse response) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + } + + public void assertQueryOffsetResponse(QueryOffsetResponse response, long offset) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getOffset()).isEqualTo(offset); + } + + public ClientSettings buildAccessPointClientSettings(int port) { + return ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setAccessPoint(Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder() + .setHost("127.0.0.1") + .setPort(port) + .build()) + .build()) + .build(); + } + + public ClientSettings buildPushConsumerClientSettings() { + return buildPushConsumerClientSettings(2, false); + } + + public ClientSettings buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + return ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PUSH_CONSUMER) + .setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() + .setMaxDeliveryAttempts(maxDeliveryAttempts) + .build()) + .setFifo(fifo) + .build()) + .build()) + .build(); + } + + public ClientSettings buildPullConsumerClientSettings() { + return ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PULL_CONSUMER) + .setSettings(Settings.newBuilder() + .build()) + .build(); + } + + public ClientSettings buildSimpleConsumerClientSettings() { + return ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.SIMPLE_CONSUMER) + .setSettings(Settings.newBuilder() + .build()) + .build(); + } + + public ClientSettings buildProducerClientSettings(String... topics) { + List topicResources = Arrays.stream(topics).map(topic -> Resource.newBuilder().setName(topic).build()) + .collect(Collectors.toList()); + return ClientSettings.newBuilder() + .setNonce(UUID.randomUUID().toString()) + .setClientType(ClientType.PRODUCER) + .setSettings(Settings.newBuilder() + .setPublishing(Publishing.newBuilder() + .addAllTopics(topicResources) + .build()) + .build()) + .build(); + } + + protected static class DefaultTelemetryCommandStreamObserver implements StreamObserver { + + @Override + public void onNext(TelemetryCommand value) { + + } + + @Override + public void onError(Throwable t) { + + } + + @Override + public void onCompleted() { + + } + } } \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index 30c7c50270..6fefd4337c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -17,13 +17,7 @@ package org.apache.rocketmq.test.grpc.v2; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.SendMessageResponse; -import java.net.URL; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; @@ -31,33 +25,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; -import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; - public class LocalGrpcTest extends GrpcBaseTest { - private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; - private MessagingServiceGrpc.MessagingServiceStub stub; private LocalGrpcService localGrpcService; @Before public void setUp() throws Exception { super.setUp(); - String mockProxyHome = "/mock/rmq/proxy/home"; - URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); - if (mockProxyHomeURL != null) { - mockProxyHome = mockProxyHomeURL.toURI().getPath(); - } - System.setProperty(RMQ_PROXY_HOME, mockProxyHome); - ConfigurationManager.initEnv(); - ConfigurationManager.intConfig(); - ConfigurationManager.getProxyConfig().setGrpcServerPort(8082); - ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); localGrpcService = new LocalGrpcService(brokerController1); localGrpcService.start(); GrpcMessagingProcessor processor = new GrpcMessagingProcessor(localGrpcService); setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); - blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); - stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); } @After @@ -67,24 +44,11 @@ public class LocalGrpcTest extends GrpcBaseTest { } @Test - public void testQueryRoute() { + public void testQueryRoute() throws Exception { String topic = initTopic(); + this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); + QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); - assertQueryRoute(response, brokerControllerList.size()); - } - - @Test - public void testSendReceiveMessage() { - String group = "group"; - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(broker1Name, messageId)); - assertSendMessage(sendResponse, messageId); - - ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); - assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); - assertAck(ackMessageResponse); + assertQueryRoute(response, brokerControllerList.size() * defaultQueueNums); } } From c7b81c13c9dc112697cfeaf07f9e72af8e2c7d65 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 14 Apr 2022 19:26:32 +0800 Subject: [PATCH 102/338] [ISSUE #3949] Add integration test * Write response when POLLING_TIMEOUT * Fix Channel isWritable * Use TransactionId in GrpcClientChannel and SendMessageResponseHandler * Optimize sendMessage and nackMessage --- .../broker/processor/PopMessageProcessor.java | 2 + .../proxy/channel/InvocationChannel.java | 15 +--- .../connector/transaction/TransactionId.java | 13 ++- .../v2/adapter/channel/GrpcClientChannel.java | 15 ++-- .../ReceiveMessageResponseHandler.java | 7 +- .../handler/SendMessageResponseHandler.java | 33 +++++-- .../grpc/v2/service/LocalGrpcService.java | 87 ++++++++++++------- .../test/grpc/v2/ClusterGrpcTest.java | 20 +++++ .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 48 ++++++++-- .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 20 +++++ 10 files changed, 192 insertions(+), 68 deletions(-) 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 7708f415ea..b4007d413d 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 @@ -454,6 +454,8 @@ public class PopMessageProcessor implements NettyRequestProcessor { response = null; } break; + case ResponseCode.POLLING_TIMEOUT: + return response; default: assert false; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java index 4e04086797..83dc2428cc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -20,7 +20,6 @@ package org.apache.rocketmq.proxy.channel; import io.netty.channel.ChannelFuture; import java.util.Iterator; import java.util.Map; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.rocketmq.proxy.common.Cleaner; @@ -50,17 +49,9 @@ public abstract class InvocationChannel extends SimpleChannel implements C return super.writeAndFlush(msg); } - public boolean isWritable(int opaque) { - if (!inFlightRequestMap.containsKey(opaque)) { - return false; - } - - InvocationContext invocationContext = inFlightRequestMap.get(opaque); - if (null != invocationContext) { - CompletableFuture future = invocationContext.getResponse(); - return null != future && !future.isCancelled() && !future.isCompletedExceptionally() && !future.isDone(); - } - return false; + @Override + public boolean isWritable() { + return inFlightRequestMap.size() > 0; } public void registerInvocationContext(int opaque, InvocationContext context) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index e680c7ad90..4a4b176cbc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -60,18 +60,18 @@ public class TransactionId { } public static TransactionId genByBrokerTransactionId(String brokerAddr, SendResult sendResult) { - MessageId id = new MessageId(null, 0); + long commitLogOffset = 0L; try { if (sendResult.getOffsetMsgId() != null) { - id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); + commitLogOffset = generateCommitLogOffset(sendResult.getOffsetMsgId()); } else { - id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); + commitLogOffset = generateCommitLogOffset(sendResult.getMsgId()); } } catch (Exception e) { log.warn("genFromBrokerTransactionId failed. brokerAddr: {}, sendResult: {}", brokerAddr, sendResult, e); } return genByBrokerTransactionId(RemotingUtil.string2SocketAddress(brokerAddr), sendResult.getTransactionId(), - id.getOffset(), sendResult.getQueueOffset()); + commitLogOffset, sendResult.getQueueOffset()); } public static TransactionId genByBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, @@ -127,6 +127,11 @@ public class TransactionId { .build(); } + public static long generateCommitLogOffset(String messageId) throws UnknownHostException { + MessageId id = MessageDecoder.decodeMessageId(messageId); + return id.getOffset(); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 2bbf6b84db..6b7ae4ce20 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -31,8 +31,10 @@ import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends SimpleChannel { @@ -116,19 +118,21 @@ public class GrpcClientChannel extends SimpleChannel { try { switch (command.getCode()) { case RequestCode.CHECK_TRANSACTION_STATE: { - final CheckTransactionStateRequestHeader requestHeader = command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + final CheckTransactionStateRequestHeader header = (CheckTransactionStateRequestHeader) command.readCustomHeader(); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); + TransactionId transactionId = TransactionId.genByBrokerTransactionId(RemotingUtil.string2SocketAddress(localAddress), + header.getTransactionId(), messageExt.getCommitLogOffset(), messageExt.getQueueOffset()); streamObserver.onNext(TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() - .setTransactionId(requestHeader.getTransactionId()) + .setTransactionId(transactionId.getProxyTransactionId()) .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) .build()) .build()); break; } case RequestCode.GET_CONSUMER_RUNNING_INFO: { - final GetConsumerRunningInfoRequestHeader requestHeader = command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); - if (!requestHeader.isJstackEnable()) { + final GetConsumerRunningInfoRequestHeader header = (GetConsumerRunningInfoRequestHeader) command.readCustomHeader(); + if (!header.isJstackEnable()) { break; } String nonce = manager.putCommand(command.getOpaque()); @@ -141,7 +145,6 @@ public class GrpcClientChannel extends SimpleChannel { } } } catch (Exception ignore) { - } } if (msg instanceof TelemetryCommand) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 88066c25d1..6d076490f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -36,8 +36,8 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; @@ -46,9 +46,11 @@ import org.slf4j.LoggerFactory; public class ReceiveMessageResponseHandler implements ResponseHandler { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private final String brokerName; private final boolean fifo; - public ReceiveMessageResponseHandler(boolean fifo) { + public ReceiveMessageResponseHandler(String brokerName, boolean fifo) { + this.brokerName = brokerName; this.fifo = fifo; } @@ -58,7 +60,6 @@ public class ReceiveMessageResponseHandler implements ResponseHandler future = context.getResponse(); - String brokerName = request.getMessageQueue().getBroker().getName(); long currentTimeInMillis = System.currentTimeMillis(); long popCosts = currentTimeInMillis - context.getTimestamp(); try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java index 0716c404f5..6f842df674 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java @@ -20,14 +20,26 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter.handler; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SendReceipt; +import java.net.UnknownHostException; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.channel.InvocationContext; +import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class SendMessageResponseHandler implements ResponseHandler { - public SendMessageResponseHandler() { + private final String messageId; + private final int sysFlag; + private final String localAddress; + + public SendMessageResponseHandler(String messageId, int sysFlag, String localAddress) { + this.messageId = messageId; + this.sysFlag = sysFlag; + this.localAddress = localAddress; } @Override public void handle(RemotingCommand responseCommand, @@ -37,17 +49,24 @@ public class SendMessageResponseHandler implements ResponseHandler messageList = GrpcConverter.buildMessage(request.getMessagesList(), topicName); - MessageBatch messageBatch = MessageBatch.generateFromList(messageList); - MessageClientIDSetter.setUniqID(messageBatch); - messageBatch.setBody(messageBatch.encode()); - command.setBody(messageBatch.encode()); + String messageId; + if (messageList.size() == 1) { + org.apache.rocketmq.common.message.Message message = messageList.get(0); + command.setBody(message.getBody()); + messageId = MessageClientIDSetter.getUniqID(message); + } else { + MessageBatch messageBatch = MessageBatch.generateFromList(messageList); + MessageClientIDSetter.setUniqID(messageBatch); + messageBatch.setBody(messageBatch.encode()); + command.setBody(messageBatch.encode()); + messageId = MessageClientIDSetter.getUniqID(messageBatch); + } command.makeCustomHeaderToNet(); - SendMessageResponseHandler handler = new SendMessageResponseHandler(); + SendMessageResponseHandler handler = new SendMessageResponseHandler(messageId, requestHeader.getSysFlag(), brokerController.getBrokerAddr()); SendMessageChannel channel = channelManager.createChannel(() -> new SendMessageChannel(handler), SendMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -249,7 +257,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); + long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, @@ -257,7 +265,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); - ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(clientSettings.getSettings().getSubscription().getFifo()); + ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), + clientSettings.getSettings().getSubscription().getFifo()); ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -304,22 +313,42 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); - command.makeCustomHeaderToNet(); - CompletableFuture future = new CompletableFuture<>(); - try { - RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() - .processRequest(channelHandlerContext, command); - NackMessageResponse response = NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .build(); - future.complete(response); - } catch (Exception e) { - log.error("Exception raised while nackMessage", e); - future.completeExceptionally(e); + + ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); + int maxReconsumeTimes = clientSettings.getSettings().getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); + if (request.getDeliveryAttempt() >= maxReconsumeTimes) { + ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + command.makeCustomHeaderToNet(); + + try { + RemotingCommand responseCommand = brokerController.getSendMessageProcessor() + .processRequest(channelHandlerContext, command); + NackMessageResponse response = NackMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + .build(); + future.complete(response); + } catch (Exception e) { + log.error("Exception raised while nackMessage", e); + future.completeExceptionally(e); + } + } else { + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); + command.makeCustomHeaderToNet(); + + try { + RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() + .processRequest(channelHandlerContext, command); + NackMessageResponse response = NackMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + .build(); + future.complete(response); + } catch (Exception e) { + log.error("Exception raised while nackMessage", e); + future.completeExceptionally(e); + } } return future; } @@ -402,7 +431,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - long pollTime = org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter.buildPollTimeFromContext(ctx); + long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 168d011795..680f8a1e2c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -76,4 +76,24 @@ public class ClusterGrpcTest extends GrpcBaseTest { assertQueryAssignment(response, brokerNum); } + + @Test + public void testSendReceiveMessage() throws Exception { + super.testSendReceiveMessage(); + } + + @Test + public void testTransactionCheckThenCommit() { + super.testTransactionCheckThenCommit(); + } + + @Test + public void testSendReceiveMessageThenToDLQ() throws Exception { + super.testSendReceiveMessageThenToDLQ(); + } + + @Test + public void testPullMessage() throws Exception { + super.testPullMessage(); + } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 5bb2471cb7..0415d6dbd1 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -30,6 +30,7 @@ import apache.rocketmq.v2.DeadLetterPolicy; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; @@ -60,7 +61,6 @@ import apache.rocketmq.v2.TransactionResolution; import apache.rocketmq.v2.TransactionSource; import com.google.protobuf.ByteString; import com.google.protobuf.Duration; -import com.google.protobuf.Timestamp; import com.google.protobuf.util.Timestamps; import io.grpc.Channel; import io.grpc.Metadata; @@ -125,6 +125,7 @@ public class GrpcBaseTest extends BaseConf { public void setUp() throws Exception { header.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); + header.put(InterceptorConstants.LANGUAGE, "JAVA"); String mockProxyHome = "/mock/rmq/proxy/home"; URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); @@ -202,7 +203,6 @@ public class GrpcBaseTest extends BaseConf { .build()); } - @Test public void testSendReceiveMessage() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; @@ -229,7 +229,6 @@ public class GrpcBaseTest extends BaseConf { assertAck(ackMessageResponse); } - @Test public void testSendReceiveMessageThenToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); this.sendClientSettings(stub, ClientSettings.newBuilder() @@ -260,7 +259,7 @@ public class GrpcBaseTest extends BaseConf { AtomicReference receiveRetryResponseRef = new AtomicReference<>(); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group); + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group, 1); if (receiveRetryResponse.getMessagesCount() <= 0) { return false; } @@ -307,17 +306,48 @@ public class GrpcBaseTest extends BaseConf { try { requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(buildProducerClientSettings(topic)) + .setClientSettings(buildPushConsumerClientSettings()) .build()); - + await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { + if (telemetryCommandRef.get() == null) { + return false; + } + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS) { + return false; + } + return telemetryCommandRef.get() != null; + }); + telemetryCommandRef.set(null); // init consumer offset receiveMessage(blockingStub, topic, group); + requestStreamObserver.onNext(TelemetryCommand.newBuilder() + .setClientSettings(buildProducerClientSettings(topic)) + .build()); + blockingStub.heartbeat(HeartbeatRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .build()); + await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { + if (telemetryCommandRef.get() == null) { + return false; + } + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS) { + return false; + } + return telemetryCommandRef.get() != null; + }); + telemetryCommandRef.set(null); + String messageId = createUniqID(); SendMessageResponse sendResponse = blockingStub.sendMessage(buildTransactionSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); await().atMost(java.time.Duration.ofSeconds(60)).until(() -> { + if (telemetryCommandRef.get() == null) { + return false; + } if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.RECOVER_ORPHANED_TRANSACTION_COMMAND) { return false; } @@ -347,7 +377,6 @@ public class GrpcBaseTest extends BaseConf { } } - @Test public void testPullMessage() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; @@ -379,6 +408,11 @@ public class GrpcBaseTest extends BaseConf { .receiveMessage(buildReceiveMessageRequest(group, topic)); } + public ReceiveMessageResponse receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group, int timeSeconds) { + return stub.withDeadlineAfter(timeSeconds, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + } + public QueryRouteRequest buildQueryRouteRequest(String topic) { return QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index 6fefd4337c..cf5023755a 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -51,4 +51,24 @@ public class LocalGrpcTest extends GrpcBaseTest { QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); assertQueryRoute(response, brokerControllerList.size() * defaultQueueNums); } + + @Test + public void testSendReceiveMessage() throws Exception { + super.testSendReceiveMessage(); + } + + @Test + public void testTransactionCheckThenCommit() { + super.testTransactionCheckThenCommit(); + } + + @Test + public void testSendReceiveMessageThenToDLQ() throws Exception { + super.testSendReceiveMessageThenToDLQ(); + } + + @Test + public void testPullMessage() throws Exception { + super.testPullMessage(); + } } From 35f06a4fd24ece1a5a13c4bc0dccb04c6a838796 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 15 Apr 2022 16:58:59 +0800 Subject: [PATCH 103/338] [ISSUE #3949] v2 client manager --- .../broker/client/ConsumerGroupEvent.java | 6 +- .../broker/client/ConsumerGroupInfo.java | 9 +- .../broker/client/ConsumerManager.java | 48 +++++-- .../DefaultConsumerIdsChangeListener.java | 2 + ...tener.java => ProducerChangeListener.java} | 4 +- .../broker/client/ProducerGroupEvent.java | 28 ++++ .../broker/client/ProducerManager.java | 27 ++-- .../broker/client/ConsumerManagerTest.java | 130 ++++++++++++++++++ .../broker/client/ProducerManagerTest.java | 45 +++++- .../proxy/channel/ChannelManager.java | 48 ++----- .../grpc/v2/service/GrpcClientManager.java | 4 + .../grpc/v2/service/LocalGrpcService.java | 44 ++++-- .../service/cluster/ForwardClientService.java | 56 ++++++-- .../grpc/v2/service/cluster/RouteService.java | 1 - 14 files changed, 366 insertions(+), 86 deletions(-) rename broker/src/main/java/org/apache/rocketmq/broker/client/{ProducerGroupOfflineListener.java => ProducerChangeListener.java} (86%) create mode 100644 broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupEvent.java create mode 100644 broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java index 717fb7085e..2318edb5f3 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java @@ -29,5 +29,9 @@ public enum ConsumerGroupEvent { /** * The group of consumer is registered. */ - REGISTER + REGISTER, + /** + * The client of this consumer is unregistered. + */ + CLIENT_UNREGISTER } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java index 09e1241518..638c522feb 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java @@ -98,23 +98,24 @@ public class ConsumerGroupInfo { return result; } - public void unregisterChannel(final ClientChannelInfo clientChannelInfo) { + public boolean unregisterChannel(final ClientChannelInfo clientChannelInfo) { ClientChannelInfo old = this.channelInfoTable.remove(clientChannelInfo.getChannel()); if (old != null) { log.info("unregister a consumer[{}] from consumerGroupInfo {}", this.groupName, old.toString()); + return true; } + return false; } - public boolean doChannelCloseEvent(final String remoteAddr, final Channel channel) { + public ClientChannelInfo doChannelCloseEvent(final String remoteAddr, final Channel channel) { final ClientChannelInfo info = this.channelInfoTable.remove(channel); if (info != null) { log.warn( "NETTY EVENT: remove not active channel[{}] from ConsumerGroupInfo groupChannelTable, consumer group: {}", info.toString(), groupName); - return true; } - return false; + return info; } /** diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java index b3bee7cdc0..2f0f9a6789 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java @@ -18,12 +18,14 @@ package org.apache.rocketmq.broker.client; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import io.netty.channel.Channel; +import java.util.concurrent.CopyOnWriteArrayList; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -40,16 +42,17 @@ public class ConsumerManager { private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120; private final ConcurrentMap consumerTable = new ConcurrentHashMap(1024); - private final ConsumerIdsChangeListener consumerIdsChangeListener; + private final List consumerIdsChangeListenerList = new CopyOnWriteArrayList<>(); protected final BrokerStatsManager brokerStatsManager; public ConsumerManager(final ConsumerIdsChangeListener consumerIdsChangeListener) { - this.consumerIdsChangeListener = consumerIdsChangeListener; + this.consumerIdsChangeListenerList.add(consumerIdsChangeListener); this.brokerStatsManager = null; } - public ConsumerManager(final ConsumerIdsChangeListener consumerIdsChangeListener, final BrokerStatsManager brokerStatsManager) { - this.consumerIdsChangeListener = consumerIdsChangeListener; + public ConsumerManager(final ConsumerIdsChangeListener consumerIdsChangeListener, + final BrokerStatsManager brokerStatsManager) { + this.consumerIdsChangeListenerList.add(consumerIdsChangeListener); this.brokerStatsManager = brokerStatsManager; } @@ -93,18 +96,19 @@ public class ConsumerManager { while (it.hasNext()) { Entry next = it.next(); ConsumerGroupInfo info = next.getValue(); - removed = info.doChannelCloseEvent(remoteAddr, channel); - if (removed) { + ClientChannelInfo clientChannelInfo = info.doChannelCloseEvent(remoteAddr, channel); + if (clientChannelInfo != null) { + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, next.getKey(), clientChannelInfo); if (info.getChannelInfoTable().isEmpty()) { ConsumerGroupInfo remove = this.consumerTable.remove(next.getKey()); if (remove != null) { LOGGER.info("unregister consumer ok, no any connection, and remove consumer group, {}", next.getKey()); - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, next.getKey()); + callConsumerIdsChangeListener(ConsumerGroupEvent.UNREGISTER, next.getKey()); } } - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, next.getKey(), info.getAllChannel()); + callConsumerIdsChangeListener(ConsumerGroupEvent.CHANGE, next.getKey(), info.getAllChannel()); } } return removed; @@ -128,14 +132,14 @@ public class ConsumerManager { if (r1 || r2) { if (isNotifyConsumerIdsChangedEnable) { - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel()); + callConsumerIdsChangeListener(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel()); } } if (null != this.brokerStatsManager) { this.brokerStatsManager.incConsumerRegisterTime((int) (System.currentTimeMillis() - start)); } - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.REGISTER, group, subList); + callConsumerIdsChangeListener(ConsumerGroupEvent.REGISTER, group, subList); return r1 || r2; } @@ -144,17 +148,20 @@ public class ConsumerManager { boolean isNotifyConsumerIdsChangedEnable) { ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group); if (null != consumerGroupInfo) { - consumerGroupInfo.unregisterChannel(clientChannelInfo); + boolean removed = consumerGroupInfo.unregisterChannel(clientChannelInfo); + if (removed) { + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); + } if (consumerGroupInfo.getChannelInfoTable().isEmpty()) { ConsumerGroupInfo remove = this.consumerTable.remove(group); if (remove != null) { LOGGER.info("unregister consumer ok, no any connection, and remove consumer group, {}", group); - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, group); + callConsumerIdsChangeListener(ConsumerGroupEvent.UNREGISTER, group); } } if (isNotifyConsumerIdsChangedEnable) { - this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel()); + callConsumerIdsChangeListener(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel()); } } } @@ -177,6 +184,7 @@ public class ConsumerManager { LOGGER.warn( "SCAN: remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}", RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group); + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); RemotingUtil.closeChannel(clientChannelInfo.getChannel()); itChannel.remove(); } @@ -204,4 +212,18 @@ public class ConsumerManager { } return groups; } + + public void appendConsumerIdsChangeListener(ConsumerIdsChangeListener listener) { + consumerIdsChangeListenerList.add(listener); + } + + protected void callConsumerIdsChangeListener(ConsumerGroupEvent event, String group, Object... args) { + for (ConsumerIdsChangeListener listener : consumerIdsChangeListenerList) { + try { + listener.handle(event, group, args); + } catch (Throwable t) { + LOGGER.error("err when call consumerIdsChangeListener", t); + } + } + } } 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 8e6e667dd3..72ccc8f16f 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 @@ -90,6 +90,8 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen Collection subscriptionDataList = (Collection) args[0]; this.brokerController.getConsumerFilterManager().register(group, subscriptionDataList); break; + case CLIENT_UNREGISTER: + break; default: throw new RuntimeException("Unknown event " + event); } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java similarity index 86% rename from broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java rename to broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java index 1107f0d9ed..576faf8a81 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupOfflineListener.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java @@ -16,7 +16,7 @@ */ package org.apache.rocketmq.broker.client; -public interface ProducerGroupOfflineListener { +public interface ProducerChangeListener { - void onOffline(String group); + void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo); } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupEvent.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupEvent.java new file mode 100644 index 0000000000..cbf27ce61e --- /dev/null +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerGroupEvent.java @@ -0,0 +1,28 @@ +/* + * 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.client; + +public enum ProducerGroupEvent { + /** + * The group of producer is unregistered. + */ + GROUP_UNREGISTER, + /** + * The client of this producer is unregistered. + */ + CLIENT_UNREGISTER +} diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java index 09da153a96..41df13f8f5 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import org.apache.rocketmq.broker.util.PositiveAtomicCounter; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; @@ -40,7 +41,7 @@ public class ProducerManager { private final ConcurrentHashMap clientChannelTable = new ConcurrentHashMap<>(); protected final BrokerStatsManager brokerStatsManager; private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter(); - private volatile ProducerGroupOfflineListener producerGroupOfflineListener; + private final List producerChangeListenerList = new CopyOnWriteArrayList<>(); public ProducerManager() { this.brokerStatsManager = null; @@ -85,6 +86,7 @@ public class ProducerManager { log.warn( "ProducerManager#scanNotActiveChannel: remove expired channel[{}] from ProducerManager groupChannelTable, producer group name: {}", RemotingHelper.parseChannelRemoteAddr(info.getChannel()), group); + callProducerChangeListener(ProducerGroupEvent.CLIENT_UNREGISTER, group, info); RemotingUtil.closeChannel(info.getChannel()); } } @@ -92,7 +94,7 @@ public class ProducerManager { if (chlMap.isEmpty()) { log.warn("SCAN: remove expired channel from ProducerManager groupChannelTable, all clear, group={}", group); iterator.remove(); - this.notifyProducerOffline(group); + callProducerChangeListener(ProducerGroupEvent.GROUP_UNREGISTER, group, null); } } } @@ -113,11 +115,12 @@ public class ProducerManager { log.info( "NETTY EVENT: remove channel[{}][{}] from ProducerManager groupChannelTable, producer group: {}", clientChannelInfo.toString(), remoteAddr, group); + callProducerChangeListener(ProducerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); if (clientChannelInfoTable.isEmpty()) { ConcurrentHashMap oldGroupTable = this.groupChannelTable.remove(group); if (oldGroupTable != null) { log.info("unregister a producer group[{}] from groupChannelTable", group); - this.notifyProducerOffline(group); + callProducerChangeListener(ProducerGroupEvent.GROUP_UNREGISTER, group, null); } } } @@ -158,11 +161,12 @@ public class ProducerManager { if (old != null) { log.info("unregister a producer[{}] from groupChannelTable {}", group, clientChannelInfo.toString()); + callProducerChangeListener(ProducerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); } if (channelTable.isEmpty()) { this.groupChannelTable.remove(group); - this.notifyProducerOffline(group); + callProducerChangeListener(ProducerGroupEvent.GROUP_UNREGISTER, group, null); log.info("unregister a producer group[{}] from groupChannelTable", group); } } @@ -212,13 +216,18 @@ public class ProducerManager { return clientChannelTable.get(clientId); } - public void notifyProducerOffline(String group) { - if (this.producerGroupOfflineListener != null) { - this.producerGroupOfflineListener.onOffline(group); + private void callProducerChangeListener(ProducerGroupEvent event, String group, + ClientChannelInfo clientChannelInfo) { + for (ProducerChangeListener listener : producerChangeListenerList) { + try { + listener.handle(event, group, clientChannelInfo); + } catch (Throwable t) { + log.error("err when call producerChangeListener", t); + } } } - public void setProducerOfflineListener(ProducerGroupOfflineListener producerGroupOfflineListener) { - this.producerGroupOfflineListener = producerGroupOfflineListener; + public void appendProducerChangeListener(ProducerChangeListener producerChangeListener) { + producerChangeListenerList.add(producerChangeListener); } } diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java new file mode 100644 index 0000000000..f6dbd3e973 --- /dev/null +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java @@ -0,0 +1,130 @@ +package org.apache.rocketmq.broker.client; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerManagerTest { + private ConsumerManager consumerManager; + private String group = "FooBar"; + private String clientId = "clientId"; + private ClientChannelInfo clientInfo; + private Map> groupEventListMap = new HashMap<>(); + + @Mock + private Channel channel; + + @Before + public void init() { + clientInfo = new ClientChannelInfo(channel, clientId, LanguageCode.JAVA, 0); + + consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { + @Override + public void handle(ConsumerGroupEvent event, String group, Object... args) { + groupEventListMap.compute(event, (eventKey, dataListVal) -> { + if (dataListVal == null) { + dataListVal = new ArrayList<>(); + } + dataListVal.add(new ConsumerIdsChangeListenerData(event, group, args)); + return dataListVal; + }); + } + + @Override + public void shutdown() { + + } + }); + } + + private static class ConsumerIdsChangeListenerData { + private ConsumerGroupEvent event; + private String group; + private Object[] args; + + public ConsumerIdsChangeListenerData(ConsumerGroupEvent event, String group, Object[] args) { + this.event = event; + this.group = group; + this.args = args; + } + } + + @Test + public void testClientUnregisterEventInDoChannelCloseEvent() { + assertThat(consumerManager.registerConsumer( + group, + clientInfo, + ConsumeType.CONSUME_PASSIVELY, + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + new HashSet<>(), + false + )).isTrue(); + + consumerManager.doChannelCloseEvent("remoteAddr", channel); + + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).size()).isEqualTo(1); + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]).isInstanceOf(ClientChannelInfo.class); + ClientChannelInfo clientChannelInfo = (ClientChannelInfo) groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]; + assertThat(clientChannelInfo).isSameAs(clientInfo); + } + + @Test + public void testClientUnregisterEventInUnregisterConsumer() { + assertThat(consumerManager.registerConsumer( + group, + clientInfo, + ConsumeType.CONSUME_PASSIVELY, + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + new HashSet<>(), + false + )).isTrue(); + + consumerManager.unregisterConsumer(group, clientInfo, false); + + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).size()).isEqualTo(1); + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]).isInstanceOf(ClientChannelInfo.class); + ClientChannelInfo clientChannelInfo = (ClientChannelInfo) groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]; + assertThat(clientChannelInfo).isSameAs(clientInfo); + } + + @Test + public void testClientUnregisterEventInScanNotActiveChannel() { + assertThat(consumerManager.registerConsumer( + group, + clientInfo, + ConsumeType.CONSUME_PASSIVELY, + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + new HashSet<>(), + false + )).isTrue(); + clientInfo.setLastUpdateTimestamp(0); + when(channel.close()).thenReturn(mock(ChannelFuture.class)); + + consumerManager.scanNotActiveChannel(); + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).size()).isEqualTo(1); + assertThat(groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]).isInstanceOf(ClientChannelInfo.class); + ClientChannelInfo clientChannelInfo = (ClientChannelInfo) groupEventListMap.get(ConsumerGroupEvent.CLIENT_UNREGISTER).get(0).args[0]; + assertThat(clientChannelInfo).isSameAs(clientInfo); + } +} \ No newline at end of file diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java index 3d05d39ef8..fd76312941 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java @@ -52,7 +52,19 @@ public class ProducerManagerTest { public void scanNotActiveChannel() throws Exception { producerManager.registerProducer(group, clientInfo); AtomicReference groupRef = new AtomicReference<>(); - producerManager.setProducerOfflineListener(groupRef::set); + AtomicReference clientChannelInfoRef = new AtomicReference<>(); + producerManager.appendProducerChangeListener((event, group, clientChannelInfo) -> { + switch (event) { + case GROUP_UNREGISTER: + groupRef.set(group); + break; + case CLIENT_UNREGISTER: + clientChannelInfoRef.set(clientChannelInfo); + break; + default: + break; + } + }); assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNotNull(); assertThat(producerManager.findChannel("clientId")).isNotNull(); Field field = ProducerManager.class.getDeclaredField("CHANNEL_EXPIRED_TIMEOUT"); @@ -63,6 +75,7 @@ public class ProducerManagerTest { producerManager.scanNotActiveChannel(); assertThat(producerManager.getGroupChannelTable().get(group)).isNull(); assertThat(groupRef.get()).isEqualTo(group); + assertThat(clientChannelInfoRef.get()).isSameAs(clientInfo); assertThat(producerManager.findChannel("clientId")).isNull(); } @@ -70,12 +83,25 @@ public class ProducerManagerTest { public void doChannelCloseEvent() throws Exception { producerManager.registerProducer(group, clientInfo); AtomicReference groupRef = new AtomicReference<>(); - producerManager.setProducerOfflineListener(groupRef::set); + AtomicReference clientChannelInfoRef = new AtomicReference<>(); + producerManager.appendProducerChangeListener((event, group, clientChannelInfo) -> { + switch (event) { + case GROUP_UNREGISTER: + groupRef.set(group); + break; + case CLIENT_UNREGISTER: + clientChannelInfoRef.set(clientChannelInfo); + break; + default: + break; + } + }); assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNotNull(); assertThat(producerManager.findChannel("clientId")).isNotNull(); producerManager.doChannelCloseEvent("127.0.0.1", channel); assertThat(producerManager.getGroupChannelTable().get(group)).isNull(); assertThat(groupRef.get()).isEqualTo(group); + assertThat(clientChannelInfoRef.get()).isSameAs(clientInfo); assertThat(producerManager.findChannel("clientId")).isNull(); } @@ -94,7 +120,19 @@ public class ProducerManagerTest { public void unregisterProducer() throws Exception { producerManager.registerProducer(group, clientInfo); AtomicReference groupRef = new AtomicReference<>(); - producerManager.setProducerOfflineListener(groupRef::set); + AtomicReference clientChannelInfoRef = new AtomicReference<>(); + producerManager.appendProducerChangeListener((event, group, clientChannelInfo) -> { + switch (event) { + case GROUP_UNREGISTER: + groupRef.set(group); + break; + case CLIENT_UNREGISTER: + clientChannelInfoRef.set(clientChannelInfo); + break; + default: + break; + } + }); Map channelMap = producerManager.getGroupChannelTable().get(group); assertThat(channelMap).isNotNull(); assertThat(channelMap.get(channel)).isEqualTo(clientInfo); @@ -105,6 +143,7 @@ public class ProducerManagerTest { channelMap = producerManager.getGroupChannelTable().get(group); channel1 = producerManager.findChannel("clientId"); assertThat(groupRef.get()).isEqualTo(group); + assertThat(clientChannelInfoRef.get()).isSameAs(clientInfo); assertThat(channelMap).isNull(); assertThat(channel1).isNull(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 5adc5e0b80..aae433f54c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -20,25 +20,22 @@ package org.apache.rocketmq.proxy.channel; import io.grpc.Context; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.common.Cleaner; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ChannelManager { private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); - private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); + private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { @@ -123,35 +120,20 @@ public class ChannelManager { return new ArrayList<>(groupClientIdMap.get(group)); } - /** - * Scan and remove inactive mocking channels; Scan and clean expired requests; - */ - public void scanAndCleanChannels() { - try { - Iterator> iterator = clientIdChannelMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (!entry.getValue().isActive()) { - iterator.remove(); - if (entry.getValue() instanceof GrpcClientChannel) { - GrpcClientChannel grpcClientChannel = (GrpcClientChannel) entry.getValue(); - groupClientIdMap.computeIfPresent(grpcClientChannel.getGroup(), (group, clientIds) -> { - clientIds.remove(grpcClientChannel.getClientId()); - if (clientIds.isEmpty()) { - return null; - } - return clientIds; - }); - } - } else { - if (entry.getValue() instanceof Cleaner) { - Cleaner cleaner = (Cleaner) entry.getValue(); - cleaner.clean(); - } + public void onClientOffline(String clientId) { + SimpleChannel simpleChannel = clientIdChannelMap.remove(clientId); + if (simpleChannel == null) { + return; + } + if (simpleChannel instanceof GrpcClientChannel) { + GrpcClientChannel grpcClientChannel = (GrpcClientChannel) simpleChannel; + groupClientIdMap.computeIfPresent(grpcClientChannel.getGroup(), (group, clientIds) -> { + clientIds.remove(grpcClientChannel.getClientId()); + if (clientIds.isEmpty()) { + return null; } - } - } catch (Throwable e) { - log.error("Unexpected exception", e); + return clientIds; + }); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index e3705c8532..f949af8ecf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -39,4 +39,8 @@ public class GrpcClientManager { public void updateClientSettings(String clientId, ClientSettings clientSettings) { CLIENT_SETTINGS_MAP.put(clientId, clientSettings); } + + public ClientSettings removeClientSettings(String clientId) { + return CLIENT_SETTINGS_MAP.remove(clientId); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 72a1701116..73998b4283 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -65,6 +65,11 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.broker.client.ProducerGroupEvent; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; @@ -91,7 +96,6 @@ import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.DelayPolicy; -import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -144,8 +148,11 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.grpcClientManager = new GrpcClientManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); + + this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); + this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); + this.appendStartAndShutdown(connectorManager); - this.appendStartAndShutdown(new LocalGrpcServiceStartAndShutdown()); } @Override @@ -615,17 +622,36 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo }; } - private class LocalGrpcServiceStartAndShutdown implements StartAndShutdown { - @Override public void start() throws Exception { - LocalGrpcService.this.scheduledExecutorService.scheduleWithFixedDelay(LocalGrpcService.this::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); + protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { + + @Override + public void handle(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]; + channelManager.onClientOffline(clientChannelInfo.getClientId()); + grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); + } + } } - @Override public void shutdown() throws Exception { - LocalGrpcService.this.scheduledExecutorService.shutdown(); + @Override + public void shutdown() { + } } - private void scanAndCleanChannels() { - this.channelManager.scanAndCleanChannels(); + protected class ProducerChangeListenerImpl implements ProducerChangeListener { + + @Override + public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { + if (event == ProducerGroupEvent.CLIENT_UNREGISTER) { + channelManager.onClientOffline(clientChannelInfo.getClientId()); + grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); + } + } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 770294eefb..cea463d2f1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -39,13 +39,15 @@ import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerGroupEvent; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.broker.client.ProducerGroupEvent; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; @@ -82,17 +84,49 @@ public class ForwardClientService extends BaseService { this.grpcClientManager = grpcClientManager; this.telemetryCommandManager = telemetryCommandManager; - this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListener() { - @Override - public void handle(ConsumerGroupEvent event, String group, Object... args) { - } - - @Override - public void shutdown() { - } - }); + this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); this.producerManager = new ProducerManager(); - this.producerManager.setProducerOfflineListener(connectorManager.getTransactionHeartbeatRegisterService()::onProducerGroupOffline); + this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); + } + + protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { + + @Override + public void handle(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]; + channelManager.onClientOffline(clientChannelInfo.getClientId()); + grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); + } + } + } + + @Override + public void shutdown() { + + } + } + + protected class ProducerChangeListenerImpl implements ProducerChangeListener { + + @Override + public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { + switch (event) { + case GROUP_UNREGISTER: + connectorManager.getTransactionHeartbeatRegisterService().onProducerGroupOffline(group); + break; + case CLIENT_UNREGISTER: + channelManager.onClientOffline(clientChannelInfo.getClientId()); + grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); + break; + default: + break; + } + } } public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 8ebea5c10a..55a62de108 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -48,7 +48,6 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; From fc492d31de1e7ab2203f0b7046f8da8e4ad9093f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 18 Apr 2022 15:14:01 +0800 Subject: [PATCH 104/338] [ISSUE #3949] Add annotation and unit test --- .../v2/adapter/channel/GrpcClientChannel.java | 6 ++ .../grpc/v2/service/LocalGrpcServiceTest.java | 68 +++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 6b7ae4ce20..9a2650239c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -109,6 +109,12 @@ public class GrpcClientChannel extends SimpleChannel { *

* Case {@link RequestCode#CHECK_TRANSACTION_STATE} * @see org.apache.rocketmq.broker.client.net.Broker2Client#checkProducerTransactionState + *

+ *

+ * Case {@link RequestCode#GET_CONSUMER_RUNNING_INFO} + * @see org.apache.rocketmq.broker.processor.AdminBrokerProcessor + * getConsumerRunningInfo + *

*/ @Override public ChannelFuture writeAndFlush(Object msg) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 0bb5eff536..c80b97291f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -24,6 +24,7 @@ import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.DeadLetterPolicy; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -47,6 +48,7 @@ import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; @@ -79,6 +81,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; @@ -148,7 +151,10 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { } }); streamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(ClientSettings.newBuilder().setSettings(Settings.getDefaultInstance())) + .setClientSettings(ClientSettings.newBuilder().setSettings(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() + .setMaxDeliveryAttempts(3).build()).build()).build())) .build()); } @@ -218,7 +224,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build(); CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + Context.current(), request); SendMessageResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()) .isEqualTo(Code.INTERNAL_SERVER_ERROR); @@ -237,7 +243,29 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build(); CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + Context.current(), request); + assertThat(grpcFuture.isDone()).isFalse(); + } + + @Test + public void testSendMessageBatchWithWriteAndFlush() throws Exception { + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(null); + SendMessageRequest request = SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("123") + .build()) + .build()) + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("124") + .build()) + .build()) + .build(); + + CompletableFuture grpcFuture = localGrpcService.sendMessage( + Context.current(), request); assertThat(grpcFuture.isDone()).isFalse(); } @@ -254,7 +282,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build(); CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(), request); + Context.current(), request); assertThatThrownBy(() -> { try { grpcFuture.get(); @@ -376,6 +404,38 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } + @Test + public void testNackMessageWhenDLQ() throws Exception { + ConsumerSendMsgBackRequestHeader responseHeader = new ConsumerSendMsgBackRequestHeader(); + RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); + + SendMessageProcessor sendMessageProcessor = Mockito.mock(SendMessageProcessor.class); + Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessor); + Mockito.when(sendMessageProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + NackMessageRequest request = NackMessageRequest.newBuilder() + .setDeliveryAttempt(3) + .setReceiptHandle( + ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topicType("topic") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode() + ).build(); + CompletableFuture grpcFuture = localGrpcService.nackMessage( + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(), request); + NackMessageResponse r = grpcFuture.get(); + assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); + } + @Test public void testForwardMessageToDeadLetterQueue() throws Exception { RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); From 4db626bdb0e7d7e0eb7cc48dfc08cabc51ece3bb Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 20 Apr 2022 20:15:06 +0800 Subject: [PATCH 105/338] [ISSUE #3949] v2 support --- pom.xml | 1 + .../rocketmq/proxy/config/ProxyConfig.java | 39 ++++- .../proxy/grpc/v2/GrpcMessagingProcessor.java | 43 +---- .../proxy/grpc/v2/adapter/GrpcConverter.java | 73 ++++---- .../grpc/v2/adapter/ResponseBuilder.java | 13 ++ .../grpc/v2/service/ClusterGrpcService.java | 19 +-- .../grpc/v2/service/GrpcClientManager.java | 65 ++++++- .../grpc/v2/service/GrpcForwardService.java | 8 - .../grpc/v2/service/LocalGrpcService.java | 97 ++--------- .../service/ReportActiveSettingsService.java | 77 +++++++++ .../v2/service/cluster/ConsumerService.java | 82 ++++++--- .../service/cluster/ForwardClientService.java | 56 ++---- .../service/cluster/PullMessageService.java | 160 ------------------ .../cluster/PullMessageServiceTest.java | 131 -------------- 14 files changed, 309 insertions(+), 555 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java diff --git a/pom.xml b/pom.xml index 467138921c..3362e6c84a 100644 --- a/pom.xml +++ b/pom.xml @@ -455,6 +455,7 @@ ${project.groupId} rocketmq-proto 2.0.0-SNAPSHOT + compatible
${project.groupId} 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 cddce40d0b..e108f8de3a 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 @@ -57,7 +57,12 @@ public class ProxyConfig { */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; - private int channelExpiredInSeconds = 120; + private int maxMessageBodyBytes = 1024 * 1024 * 4; + private int defaultMessageBodyCompressionBytesThreshold = 1024 * 4; + private int defaultTransactionRecoverySecond = 30; + private int defaultMaxDeliveryAttempts = 16; + + private int channelExpiredInSeconds = 60; private int forwardConsumerNum = 2; private double forwardConsumerWorkerFactor = 0.2f; @@ -237,6 +242,38 @@ public class ProxyConfig { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } + public int getMaxMessageBodyBytes() { + return maxMessageBodyBytes; + } + + public void setMaxMessageBodyBytes(int maxMessageBodyBytes) { + this.maxMessageBodyBytes = maxMessageBodyBytes; + } + + public int getDefaultMessageBodyCompressionBytesThreshold() { + return defaultMessageBodyCompressionBytesThreshold; + } + + public void setDefaultMessageBodyCompressionBytesThreshold(int defaultMessageBodyCompressionBytesThreshold) { + this.defaultMessageBodyCompressionBytesThreshold = defaultMessageBodyCompressionBytesThreshold; + } + + public int getDefaultTransactionRecoverySecond() { + return defaultTransactionRecoverySecond; + } + + public void setDefaultTransactionRecoverySecond(int defaultTransactionRecoverySecond) { + this.defaultTransactionRecoverySecond = defaultTransactionRecoverySecond; + } + + public int getDefaultMaxDeliveryAttempts() { + return defaultMaxDeliveryAttempts; + } + + public void setDefaultMaxDeliveryAttempts(int defaultMaxDeliveryAttempts) { + this.defaultMaxDeliveryAttempts = defaultMaxDeliveryAttempts; + } + public int getChannelExpiredInSeconds() { return channelExpiredInSeconds; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index 87cc060e09..53f9fecfde 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -21,7 +21,6 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -33,12 +32,8 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -50,8 +45,6 @@ import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; @@ -64,14 +57,8 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic this.grpcForwardService = grpcForwardService; } - public Status convertExceptionToStatus(Throwable t) { - if (t instanceof CompletionException) { - if (t.getCause() instanceof ProxyException) { - ProxyException proxyException = (ProxyException) t.getCause(); - return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); - } - } - return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); + protected Status convertExceptionToStatus(Throwable t) { + return ResponseBuilder.buildStatus(t); } @Override @@ -193,32 +180,6 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic }); } - @Override - public void queryOffset(QueryOffsetRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryOffset(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryOffsetResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - } - - @Override - public void pullMessage(PullMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.pullMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - PullMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - } - @Override public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index a67844a85a..cbb5bb6dcd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -18,14 +18,15 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Digest; import apache.rocketmq.v2.DigestType; import apache.rocketmq.v2.Encoding; import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -35,7 +36,8 @@ import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.PullMessageRequest; +import apache.rocketmq.v2.PassivePublishingSettings; +import apache.rocketmq.v2.PassiveSubscriptionSettings; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; @@ -78,7 +80,6 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHead import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -86,12 +87,13 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,13 +105,13 @@ public class GrpcConverter { } public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, - ClientSettings clientSettings) { + GrpcClientManager.ActiveClientSettings clientSettings) { HeartbeatData heartbeatData = new HeartbeatData(); heartbeatData.setClientID(clientId); switch (clientSettings.getClientType()) { case PRODUCER: { Set producerDataSet = new HashSet<>(); - for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { String topicName = wrapResourceWithNamespace(topic); producerDataSet.add(buildProducerData(topicName)); } @@ -137,7 +139,7 @@ public class GrpcConverter { } public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, - ClientSettings clientSettings) { + GrpcClientManager.ActiveClientSettings clientSettings) { org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); buildConsumerData.setGroupName(groupName); buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); @@ -145,9 +147,7 @@ public class GrpcConverter { buildConsumerData.setMessageModel(MessageModel.CLUSTERING); buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); Set subscriptionDataSet = - buildSubscriptionDataSet(clientSettings.getSettings() - .getSubscription() - .getSubscriptionsList()); + buildSubscriptionDataSet(clientSettings.getActiveSubscriptionSettings().getSubscriptionsList()); buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); return buildConsumerData; } @@ -241,10 +241,9 @@ public class GrpcConverter { return requestHeader; } - public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { + public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); ackMessageRequestHeader.setConsumerGroup(groupName); @@ -360,32 +359,6 @@ public class GrpcConverter { return endTransactionRequestHeader; } - public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, - long pollTimeoutInMillis) { - MessageQueue messageQueue = request.getMessageQueue(); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(messageQueue.getTopic()); - - int queueId = messageQueue.getId(); - int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); - String expression = request.getFilterExpression().getExpression(); - String expressionType = GrpcConverter.buildExpressionType(request.getFilterExpression().getType()); - - PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); - requestHeader.setConsumerGroup(groupName); - requestHeader.setTopic(topicName); - requestHeader.setQueueId(queueId); - requestHeader.setQueueOffset(request.getOffset()); - requestHeader.setMaxMsgNums(request.getBatchSize()); - requestHeader.setSysFlag(sysFlag); - requestHeader.setCommitOffset(0L); - requestHeader.setSuspendTimeoutMillis(pollTimeoutInMillis); - requestHeader.setSubscription(expression); - requestHeader.setSubVersion(0L); - requestHeader.setExpressionType(expressionType); - return requestHeader; - } - public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, ClientType clientType, NotifyClientTerminationRequest request) { UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); @@ -535,6 +508,30 @@ public class GrpcConverter { .build(); } + public static ApplyPassiveSettingsCommand buildDefaultPublishingSettings(String nonce, Endpoints traceEndpoint) { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + return ApplyPassiveSettingsCommand.newBuilder() + .setNonce(nonce) + .setTraceAccessPoint(traceEndpoint) + .setPassivePublishingSettings(PassivePublishingSettings.newBuilder() + .setMaxMessageBodyBytes(proxyConfig.getMaxMessageBodyBytes()) + .setMessageBodyCompressionBytesThreshold(proxyConfig.getDefaultMessageBodyCompressionBytesThreshold()) + .setOrphanedTransactionRecoveryDuration(Durations.fromSeconds(proxyConfig.getDefaultTransactionRecoverySecond())) + .build()) + .build(); + } + + public static ApplyPassiveSettingsCommand buildDefaultSubscriptionSettings(String nonce, Endpoints traceEndpoint) { + // TODO: read config from subscriptionGroupManager + return ApplyPassiveSettingsCommand.newBuilder() + .setNonce(nonce) + .setTraceAccessPoint(traceEndpoint) + .setPassiveSubscriptionSettings(PassiveSubscriptionSettings.newBuilder() + .setFifo(false) + .build()) + .build(); + } + protected static Map buildUserAttributes(MessageExt messageExt) { Map userAttributes = new HashMap<>(); Map properties = messageExt.getProperties(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index eecc19f53c..27be2f4333 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -19,9 +19,22 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Status; +import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.protocol.ResponseCode; public class ResponseBuilder { + + public static Status buildStatus(Throwable t) { + if (t instanceof CompletionException) { + t = t.getCause(); + } + if (t instanceof ProxyException) { + ProxyException proxyException = (ProxyException) t.getCause(); + return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); + } + return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); + } + public static Status buildStatus(Code code, String message) { return Status.newBuilder() .setCode(code) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index b44d958a50..100792bf6f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -31,12 +31,8 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -54,15 +50,14 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.PullMessageService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; import org.slf4j.Logger; @@ -81,7 +76,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc private final ConsumerService consumerService; private final RouteService routeService; private final ForwardClientService clientService; - private final PullMessageService pullMessageService; private final TransactionService transactionService; private final TelemetryCommandManager pollCommandResponseManager; private final GrpcClientManager grpcClientManager; @@ -96,7 +90,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager, grpcClientManager); this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, grpcClientManager, pollCommandResponseManager); - this.pullMessageService = new PullMessageService(connectorManager); this.transactionService = new TransactionService(connectorManager, channelManager); this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); @@ -149,16 +142,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return transactionService.endTransaction(ctx, request); } - @Override - public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return pullMessageService.queryOffset(ctx, request); - } - - @Override - public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return pullMessageService.pullMessage(ctx, request); - } - @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index f949af8ecf..3042735a04 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -17,7 +17,12 @@ package org.apache.rocketmq.proxy.grpc.v2.service; -import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ActivePublishingSettings; +import apache.rocketmq.v2.ActiveSubscriptionSettings; +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.ReportActiveSettingsCommand; +import com.google.protobuf.Duration; import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -25,22 +30,68 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { - private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); + public static class ActiveClientSettings { + private ClientType clientType; + private Endpoints accessPoint; + private Duration connectionTimeout; + private boolean traceOn = true; + private ActivePublishingSettings activePublishingSettings; + private ActiveSubscriptionSettings activeSubscriptionSettings; - public ClientSettings getClientSettings(Context ctx) { + public ActiveClientSettings(ReportActiveSettingsCommand reportActiveSettingsCommand) { + this.clientType = reportActiveSettingsCommand.getClientType(); + this.accessPoint = reportActiveSettingsCommand.getAccessPoint(); + this.connectionTimeout = reportActiveSettingsCommand.getConnectionTimeout(); + this.traceOn = reportActiveSettingsCommand.getTraceOn(); + if (reportActiveSettingsCommand.hasActivePublishingSettings()) { + this.activePublishingSettings = reportActiveSettingsCommand.getActivePublishingSettings(); + } + if (reportActiveSettingsCommand.hasActiveSubscriptionSettings()) { + this.activeSubscriptionSettings = reportActiveSettingsCommand.getActiveSubscriptionSettings(); + } + } + + public ClientType getClientType() { + return clientType; + } + + public Endpoints getAccessPoint() { + return accessPoint; + } + + public Duration getConnectionTimeout() { + return connectionTimeout; + } + + public boolean isTraceOn() { + return traceOn; + } + + public ActivePublishingSettings getActivePublishingSettings() { + return activePublishingSettings; + } + + public ActiveSubscriptionSettings getActiveSubscriptionSettings() { + return activeSubscriptionSettings; + } + } + + private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); + + public ActiveClientSettings getClientSettings(Context ctx) { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); return CLIENT_SETTINGS_MAP.get(clientId); } - public ClientSettings getClientSettings(String clientId) { + public ActiveClientSettings getClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.get(clientId); } - public void updateClientSettings(String clientId, ClientSettings clientSettings) { - CLIENT_SETTINGS_MAP.put(clientId, clientSettings); + public void updateClientSettings(String clientId, ReportActiveSettingsCommand reportActiveSettingsCommand) { + CLIENT_SETTINGS_MAP.put(clientId, new ActiveClientSettings(reportActiveSettingsCommand)); } - public ClientSettings removeClientSettings(String clientId) { + public ActiveClientSettings removeClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.remove(clientId); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java index eb11cf4ade..f7bf6f946a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java @@ -31,12 +31,8 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -69,10 +65,6 @@ public interface GrpcForwardService extends StartAndShutdown { CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); - CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request); - - CompletableFuture pullMessage(Context ctx, PullMessageRequest request); - CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 73998b4283..bca408ee58 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -98,6 +98,7 @@ import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; @@ -128,6 +129,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final TelemetryCommandManager telemetryCommandManager; private final GrpcClientManager grpcClientManager; private final RouteService routeService; + private final ReportActiveSettingsService reportActiveSettingsService; private final DelayPolicy delayPolicy; public LocalGrpcService(BrokerController brokerController) { @@ -147,6 +149,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.telemetryCommandManager = telemetryCommandManager; this.grpcClientManager = new GrpcClientManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); + this.reportActiveSettingsService = new ReportActiveSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); @@ -167,7 +170,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); languageCode = LanguageCode.valueOf(language); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -178,7 +181,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo CompletableFuture future = new CompletableFuture<>(); switch (clientSettings.getClientType()) { case PRODUCER: { - for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); @@ -266,14 +269,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); - PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, - clientSettings.getSettings().getSubscription().getFifo()); + // TODO: get fifo config from subscriptionGroupManager + boolean fifo = false; + PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), - clientSettings.getSettings().getSubscription().getFifo()); + fifo); ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -322,8 +325,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); - ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); - int maxReconsumeTimes = clientSettings.getSettings().getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); + int maxReconsumeTimes = ConfigurationManager.getProxyConfig().getDefaultMaxDeliveryAttempts(); if (request.getDeliveryAttempt() >= maxReconsumeTimes) { ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); @@ -414,56 +416,6 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override - public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - int queueId = request.getMessageQueue().getId(); - - long offset; - if (request.getPolicy() == QueryOffsetPolicy.BEGINNING) { - offset = 0L; - } else if (request.getPolicy() == QueryOffsetPolicy.END) { - offset = brokerController.getMessageStore() - .getMaxOffsetInQueue(topicName, queueId); - } else { - long timestamp = Timestamps.toMillis(request.getTimePoint()); - offset = brokerController.getMessageStore() - .getOffsetInQueueByTime(topicName, queueId, timestamp); - } - return CompletableFuture.completedFuture(QueryOffsetResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "ok")) - .setOffset(offset) - .build()); - } - - @Override - public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); - PullMessageRequestHeader requestHeader = GrpcConverter.buildPullMessageRequestHeader(request, pollTime); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); - command.makeCustomHeaderToNet(); - - PullMessageResponseHandler handler = new PullMessageResponseHandler(); - PullMessageChannel channel = channelManager.createChannel(() -> new PullMessageChannel(handler), PullMessageChannel.class); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture future = new CompletableFuture<>(); - InvocationContext context = new InvocationContext<>(request, future); - channel.registerInvocationContext(command.getOpaque(), context); - try { - RemotingCommand response = brokerController.getPullMessageProcessor() - .processRequest(channelHandlerContext, command); - if (response != null) { - handler.handle(response, context); - channel.eraseInvocationContext(command.getOpaque()); - } - } catch (Exception e) { - log.error("Failed to process pull message command", e); - channel.eraseInvocationContext(command.getOpaque()); - future.completeExceptionally(e); - } - return future; - } - public void reportThreadStackTrace(ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); @@ -510,7 +462,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); @@ -569,31 +521,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public void onNext(TelemetryCommand request) { switch (request.getCommandCase()) { - case CLIENT_SETTINGS: { - ClientSettings clientSettings = request.getClientSettings(); - grpcClientManager.updateClientSettings(clientId, clientSettings); - Settings settings = clientSettings.getSettings(); - if (settings.hasPublishing()) { - Publishing publishing = settings.getPublishing(); - for (Resource topic : publishing.getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); - producerChannel.setClientObserver(responseObserver); - } - } - if (settings.hasSubscription()) { - Subscription subscription = settings.getSubscription(); - String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); - consumerChannel.setClientObserver(responseObserver); - } - responseObserver.onNext(TelemetryCommand.newBuilder() - .setClientOverwrittenSettings(ClientOverwrittenSettings.newBuilder() - .setNonce(clientSettings.getNonce()) - .setDirection(Direction.RESPONSE) - .setSettings(settings) - .build()) - .build()); + case REPORT_ACTIVE_SETTINGS_COMMAND: { + responseObserver.onNext(reportActiveSettingsService.processReportActiveSettingsCommand(ctx, request, responseObserver)); break; } case THREAD_STACK_TRACE: { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java new file mode 100644 index 0000000000..6a771fcd0c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java @@ -0,0 +1,77 @@ +/* + * 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.grpc.v2.service; + +import apache.rocketmq.v2.ActiveSubscriptionSettings; +import apache.rocketmq.v2.ApplyPassiveSettingsCommand; +import apache.rocketmq.v2.ReportActiveSettingsCommand; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; + +public class ReportActiveSettingsService { + + private final ChannelManager channelManager; + private final GrpcClientManager grpcClientManager; + private final TelemetryCommandManager telemetryCommandManager; + + public ReportActiveSettingsService(ChannelManager channelManager, + GrpcClientManager grpcClientManager, + TelemetryCommandManager telemetryCommandManager) { + this.channelManager = channelManager; + this.grpcClientManager = grpcClientManager; + this.telemetryCommandManager = telemetryCommandManager; + } + + public TelemetryCommand processReportActiveSettingsCommand(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); + ReportActiveSettingsCommand reportActiveSettings = request.getReportActiveSettingsCommand(); + grpcClientManager.updateClientSettings(clientId, reportActiveSettings); + ApplyPassiveSettingsCommand applyPassiveSettingsCommand = ApplyPassiveSettingsCommand.getDefaultInstance(); + if (reportActiveSettings.hasActivePublishingSettings()) { + for (Resource topic : reportActiveSettings.getActivePublishingSettings().getPublishingTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); + producerChannel.setClientObserver(responseObserver); + } + applyPassiveSettingsCommand = GrpcConverter.buildDefaultPublishingSettings( + reportActiveSettings.getNonce(), + reportActiveSettings.getAccessPoint() + ); + } + if (reportActiveSettings.hasActiveSubscriptionSettings()) { + ActiveSubscriptionSettings subscription = reportActiveSettings.getActiveSubscriptionSettings(); + String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); + GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); + consumerChannel.setClientObserver(responseObserver); + applyPassiveSettingsCommand = GrpcConverter.buildDefaultSubscriptionSettings( + reportActiveSettings.getNonce(), + reportActiveSettings.getAccessPoint() + ); + } + return TelemetryCommand.newBuilder() + .setApplyPassiveSettingsCommand(applyPassiveSettingsCommand) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 1c80d715c5..c9d2fceebc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -16,8 +16,10 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; @@ -26,7 +28,6 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; import java.util.List; @@ -130,8 +131,8 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - boolean isFifo = grpcClientManager.getClientSettings(ctx).getSettings().getSubscription().getFifo(); - return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), isFifo); + // TODO: get fifo config from subscriptionGroupManager + return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), false); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { @@ -209,40 +210,70 @@ public class ConsumerService extends BaseService { }); try { - ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); - String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - - AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request); - CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader); - ackResultFuture - .thenAccept(result -> { - try { - future.complete(convertToAckMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { + CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; + for (int i = 0; i < request.getEntriesCount(); i++) { + futures[i] = processAckMessage(ctx, request, request.getEntries(i)); + } + CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { + if (throwable != null) { future.completeExceptionally(throwable); - return null; - }); + return; + } + List entryList = new ArrayList<>(); + for (CompletableFuture entryFuture : futures) { + entryFuture.thenAccept(entryList::add); + } + AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllEntries(entryList); + future.complete(responseBuilder.build()); + }); } catch (Throwable t) { future.completeExceptionally(t); } return future; } - protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request) { - return GrpcConverter.buildAckMessageRequestHeader(request); + protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, AckMessageEntry ackMessageEntry) { + CompletableFuture future = new CompletableFuture<>(); + AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()); + + try { + ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); + String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); + + AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); + CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader); + ackResultFuture + .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) + .exceptionally(throwable -> { + future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); + return null; + }); + } catch (Throwable t) { + future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); + } + return future; } - protected AckMessageResponse convertToAckMessageResponse(Context ctx, AckMessageRequest request, AckResult ackResult) { + protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, ReceiptHandle handle) { + return GrpcConverter.buildAckMessageRequestHeader(request, handle); + } + + protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { - return AckMessageResponse.newBuilder() + return AckMessageResultEntry.newBuilder() + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()) .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build(); } - return AckMessageResponse.newBuilder() + return AckMessageResultEntry.newBuilder() + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()) .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) .build(); } @@ -258,8 +289,7 @@ public class ConsumerService extends BaseService { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - Settings settings = grpcClientManager.getClientSettings(ctx).getSettings(); - int maxDeliveryAttempts = settings.getSubscription().getDeadLetterPolicy().getMaxDeliveryAttempts(); + int maxDeliveryAttempts = ConfigurationManager.getProxyConfig().getDefaultMaxDeliveryAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( brokerAddr, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index cea463d2f1..b25a3f4934 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -16,18 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.ClientOverwrittenSettings; -import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ActiveSubscriptionSettings; +import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Direction; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; @@ -54,6 +51,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.proxy.grpc.v2.service.ReportActiveSettingsService; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,6 +64,7 @@ public class ForwardClientService extends BaseService { private final ProducerManager producerManager; private final GrpcClientManager grpcClientManager; private final TelemetryCommandManager telemetryCommandManager; + private final ReportActiveSettingsService reportActiveSettingsService; public ForwardClientService( ConnectorManager connectorManager, @@ -84,6 +83,8 @@ public class ForwardClientService extends BaseService { this.grpcClientManager = grpcClientManager; this.telemetryCommandManager = telemetryCommandManager; + this.reportActiveSettingsService = new ReportActiveSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); + this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); this.producerManager = new ProducerManager(); this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); @@ -137,15 +138,16 @@ public class ForwardClientService extends BaseService { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); LanguageCode languageCode = LanguageCode.valueOf(language); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); switch (clientSettings.getClientType()) { case PRODUCER: { - for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); // use topic name as producer group producerManager.registerProducer(topicName, clientChannelInfo); + connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); } break; } @@ -165,9 +167,7 @@ public class ForwardClientService extends BaseService { GrpcConverter.buildConsumeType(clientSettings.getClientType()), MessageModel.CLUSTERING, ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, - GrpcConverter.buildSubscriptionDataSet(clientSettings.getSettings() - .getSubscription() - .getSubscriptionsList()), + GrpcConverter.buildSubscriptionDataSet(clientSettings.getActiveSubscriptionSettings().getSubscriptionsList()), false ); break; @@ -191,11 +191,11 @@ public class ForwardClientService extends BaseService { try { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); switch (clientSettings.getClientType()) { case PRODUCER: - for (Resource topic : clientSettings.getSettings().getPublishing().getTopicsList()) { + for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); // user topic name as producer group GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); @@ -229,37 +229,11 @@ public class ForwardClientService extends BaseService { } public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); return new StreamObserver() { @Override public void onNext(TelemetryCommand request) { - if (request.getCommandCase() == TelemetryCommand.CommandCase.CLIENT_SETTINGS) { - ClientSettings clientSettings = request.getClientSettings(); - grpcClientManager.updateClientSettings(clientId, clientSettings); - Settings settings = clientSettings.getSettings(); - if (settings.hasPublishing()) { - Publishing publishing = settings.getPublishing(); - for (Resource topic : publishing.getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - // use topic name as producer group - connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); - GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); - producerChannel.setClientObserver(responseObserver); - } - } - if (settings.hasSubscription()) { - Subscription subscription = settings.getSubscription(); - String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); - consumerChannel.setClientObserver(responseObserver); - } - responseObserver.onNext(TelemetryCommand.newBuilder() - .setClientOverwrittenSettings(ClientOverwrittenSettings.newBuilder() - .setNonce(clientSettings.getNonce()) - .setDirection(Direction.RESPONSE) - .setSettings(settings) - .build()) - .build()); + if (request.getCommandCase() == TelemetryCommand.CommandCase.REPORT_ACTIVE_SETTINGS_COMMAND) { + responseObserver.onNext(reportActiveSettingsService.processReportActiveSettingsCommand(ctx, request, responseObserver)); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java deleted file mode 100644 index 91194ffb66..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageService.java +++ /dev/null @@ -1,160 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; -import com.google.protobuf.util.Timestamps; -import io.grpc.Context; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.consumer.PullStatus; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtils; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.DefaultForwardClient; -import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; - -public class PullMessageService extends BaseService { - private final DefaultForwardClient forwardClient; - private final ForwardReadConsumer readConsumer; - - private volatile ResponseHook queryOffsetHook; - private volatile ResponseHook pullMessageHook; - - public PullMessageService(ConnectorManager connectorManager) { - super(connectorManager); - this.forwardClient = connectorManager.getDefaultForwardClient(); - this.readConsumer = connectorManager.getForwardReadConsumer(); - } - - public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (queryOffsetHook != null) { - queryOffsetHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - MessageQueue messageQueue = request.getMessageQueue(); - String topic = GrpcConverter.wrapResourceWithNamespace(messageQueue.getTopic()); - String brokerName = messageQueue.getBroker().getName(); - int queueId = messageQueue.getId(); - - CompletableFuture offsetFuture; - switch (request.getPolicy()) { - case BEGINNING: - offsetFuture = CompletableFuture.completedFuture(0L); - break; - case END: - offsetFuture = this.forwardClient.getMaxOffset(this.getBrokerAddr(ctx, brokerName), topic, queueId); - break; - default: - long timestamp = Timestamps.toMillis(request.getTimePoint()); - offsetFuture = this.forwardClient.searchOffset(this.getBrokerAddr(ctx, brokerName), topic, queueId, timestamp); - } - - offsetFuture - .thenAccept(result -> future.complete( - QueryOffsetResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .setOffset(result) - .build())) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (pullMessageHook != null) { - pullMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - PullMessageRequestHeader requestHeader = this.buildPullMessageRequestHeader(ctx, request); - - String brokerName = request.getMessageQueue().getBroker().getName(); - String brokerAddr = this.getBrokerAddr(ctx, brokerName); - - CompletableFuture pullResultFuture = this.readConsumer.pullMessage(brokerAddr, requestHeader); - pullResultFuture - .thenAccept(pullResult -> { - try { - future.complete(convertToPullMessageResponse(ctx, request, pullResult)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); - - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - protected PullMessageRequestHeader buildPullMessageRequestHeader(Context ctx, PullMessageRequest request) { - checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - return GrpcConverter.buildPullMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx)); - } - - protected PullMessageResponse convertToPullMessageResponse(Context ctx, PullMessageRequest request, PullResult result) { - PullMessageResponse.Builder responseBuilder = PullMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .setMinOffset(result.getMinOffset()) - .setMaxOffset(result.getMaxOffset()) - .setNextOffset(result.getNextBeginOffset()); - - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData( - GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), request.getFilterExpression()); - - PullStatus status = result.getPullStatus(); - if (status.equals(PullStatus.FOUND)) { - List messageList = result.getMsgFoundList().stream() - .filter(msg -> FilterUtils.isTagMatched(subscriptionData.getTagsSet(), msg.getTags())) // only return tag matched messages. - .map(GrpcConverter::buildMessage) - .collect(Collectors.toList()); - - return responseBuilder.addAllMessages(messageList).build(); - } else { - return responseBuilder.build(); - } - } -} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java deleted file mode 100644 index 23060b1b86..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/PullMessageServiceTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.FilterType; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; -import apache.rocketmq.v2.QueryOffsetPolicy; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; -import apache.rocketmq.v2.Resource; -import com.google.protobuf.util.Timestamps; -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.consumer.PullStatus; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.assertj.core.util.Lists; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.when; - -public class PullMessageServiceTest extends BaseServiceTest { - - private PullMessageService pullMessageService; - - @Override - public void beforeEach() throws Throwable { - pullMessageService = new PullMessageService(this.connectorManager); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - } - - @Test - public void testQueryOffset() throws Exception { - Context ctx = Context.current(); - - when(defaultClient.getMaxOffset(anyString(), anyString(), anyInt())).thenReturn(CompletableFuture.completedFuture(100L)); - when(defaultClient.searchOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(CompletableFuture.completedFuture(50L)); - - QueryOffsetResponse response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setBroker(Broker.newBuilder().setName("brokerName").build()) - .build()) - .setPolicy(QueryOffsetPolicy.BEGINNING) - .build() - ).get(); - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(0, response.getOffset()); - - response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setBroker(Broker.newBuilder().setName("brokerName").build()) - .build()) - .setPolicy(QueryOffsetPolicy.END) - .build() - ).get(); - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(100, response.getOffset()); - - response = pullMessageService.queryOffset(ctx, QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setBroker(Broker.newBuilder().setName("brokerName").build()) - .build()) - .setTimePoint(Timestamps.fromMillis(System.currentTimeMillis())) - .setPolicy(QueryOffsetPolicy.TIME_POINT) - .build() - ).get(); - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(50, response.getOffset()); - } - - @Test - public void testPullMessage() throws Exception { - AtomicReference headerRef = new AtomicReference<>(); - PullResult pullResult = new PullResult( - PullStatus.FOUND, - 3, - 0, - 10, - Lists.newArrayList( - createMessageExt("msg1", "msg1"), - createMessageExt("msg2", "msg2") - ) - ); - doAnswer(mock -> { - headerRef.set(mock.getArgument(1)); - return CompletableFuture.completedFuture(pullResult); - }).when(readConsumerClient).pullMessage(anyString(), any()); - - Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); - PullMessageResponse response = pullMessageService.pullMessage(ctx, PullMessageRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setBroker(Broker.newBuilder() - .setName("brokerName") - .build()) - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .build()) - .setFilterExpression(FilterExpression.newBuilder() - .setExpression("msg1") - .setType(FilterType.TAG) - .build()) - .build()) - .get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(1, response.getMessagesCount()); - assertEquals("msg1", response.getMessages(0).getSystemProperties().getMessageId()); - } -} \ No newline at end of file From f93f2a3ad34ca4fbd23fc7189c0bbbd648773d3e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 20 Apr 2022 20:52:56 +0800 Subject: [PATCH 106/338] [ISSUE #3949] v2 support --- .../grpc/v2/service/cluster/RouteService.java | 5 +- .../service/cluster/ConsumerServiceTest.java | 37 ++------- .../cluster/ForwardClientServiceTest.java | 36 ++++----- .../v2/service/cluster/RouteServiceTest.java | 76 ++++++------------- 4 files changed, 48 insertions(+), 106 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 55a62de108..04619890f3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -20,7 +20,6 @@ import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.Assignment; import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.MessageQueue; @@ -113,7 +112,7 @@ public class RouteService extends BaseService { List messageQueueList = new ArrayList<>(); if (ProxyMode.isClusterMode(mode.name())) { - ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() @@ -244,7 +243,7 @@ public class RouteService extends BaseService { } } if (ProxyMode.isClusterMode(mode)) { - ClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); + GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 5efa590fba..5a37e6a910 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -1,10 +1,9 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.DeadLetterPolicy; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.NackMessageRequest; @@ -12,8 +11,6 @@ import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -30,6 +27,7 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; @@ -62,15 +60,6 @@ public class ConsumerServiceTest extends BaseServiceTest { new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setFifo(false) - .build()) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - List messageExtList = Lists.newArrayList( createMessageExt("msg1", "msg1"), createMessageExt("msg2", "msg2") @@ -120,7 +109,9 @@ public class ConsumerServiceTest extends BaseServiceTest { .setGroup(Resource.newBuilder() .setName("group") .build()) - .setReceiptHandle(createReceiptHandle().encode()) + .addEntries(AckMessageEntry.newBuilder() + .setMessageId("msgId") + .setReceiptHandle(createReceiptHandle().encode())) .build()) .get(); @@ -137,8 +128,7 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(producerClient).sendMessageBack(anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - ClientSettings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(3); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -168,8 +158,7 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - ClientSettings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(3); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -187,16 +176,4 @@ public class ConsumerServiceTest extends BaseServiceTest { assertEquals(receiptHandle.getOffset(), headerRef.get().getOffset().longValue()); assertEquals(receiptHandle.encode(), headerRef.get().getExtraInfo()); } - - private ClientSettings createClientSettings(int maxDeliveryAttempts) { - return ClientSettings.newBuilder() - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() - .setMaxDeliveryAttempts(maxDeliveryAttempts) - .build()) - .build()) - .build()) - .build(); - } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index 32aacfb3d4..21a37ef5de 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -1,15 +1,14 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ActivePublishingSettings; +import apache.rocketmq.v2.ActiveSubscriptionSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SubscriptionEntry; import io.grpc.Context; import io.netty.channel.Channel; @@ -24,6 +23,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; @@ -52,19 +52,17 @@ public class ForwardClientServiceTest extends BaseServiceTest { @Test public void testProducerHeartbeat() { - ClientSettings clientSettings = ClientSettings.newBuilder() + GrpcClientManager.ActiveClientSettings clientSettings = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() .setClientType(ClientType.PRODUCER) - .setSettings(Settings.newBuilder() - .setPublishing(Publishing.newBuilder() - .addTopics(Resource.newBuilder() - .setName("topic1") - .build()) - .addTopics(Resource.newBuilder() - .setName("topic2") - .build()) + .setActivePublishingSettings(ActivePublishingSettings.newBuilder() + .addPublishingTopics(Resource.newBuilder() + .setName("topic1") + .build()) + .addPublishingTopics(Resource.newBuilder() + .setName("topic2") .build()) .build()) - .build(); + .build()); when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); @@ -91,14 +89,12 @@ public class ForwardClientServiceTest extends BaseServiceTest { .build()) .build()); - ClientSettings clientSettings = ClientSettings.newBuilder() + GrpcClientManager.ActiveClientSettings clientSettings = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .addAllSubscriptions(subscriptionEntryList) - .build()) + .setActiveSubscriptionSettings(ActiveSubscriptionSettings.newBuilder() + .addAllSubscriptions(subscriptionEntryList) .build()) - .build(); + .build()); when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 62ca554f38..44963565e6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -20,7 +20,6 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.MessageQueue; @@ -29,6 +28,7 @@ import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; import com.google.common.net.HostAndPort; import io.grpc.Context; @@ -44,6 +44,7 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -62,6 +63,20 @@ public class RouteServiceTest extends BaseServiceTest { .setResourceNamespace(NAMESPACE) .build(); + private static final GrpcClientManager.ActiveClientSettings WITH_HOST_SETTINGS = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + .setAccessPoint(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .buildPartial()); + + private static final GrpcClientManager.ActiveClientSettings INVALID_HOST_SETTINGS = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + .setAccessPoint(Endpoints.getDefaultInstance()) + .buildPartial()); + @Override public void beforeEach() throws Exception { TopicRouteData routeData = new TopicRouteData(); @@ -150,16 +165,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testLocalModeQueryRoute() throws Exception { RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -177,7 +183,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryRouteWithInvalidEndpoints() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(ClientSettings.getDefaultInstance()); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() .setName("topic") @@ -192,16 +198,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryRoute() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -220,16 +217,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryRouteWhenTopicNotExist() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -245,7 +233,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryAssignmentInvalidEndpoints() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(ClientSettings.getDefaultInstance()); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic( Resource.newBuilder() @@ -262,16 +250,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testLocalModeQueryAssignment() throws Exception { RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -293,16 +272,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testQueryAssignment() throws Exception { RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - ClientSettings clientSettings = ClientSettings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic(Resource.newBuilder() From 2c53e88f6cd8e6301da7ae5ca6f58ae5ebfd2d68 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 21 Apr 2022 17:42:44 +0800 Subject: [PATCH 107/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/adapter/RequestMapping.java | 4 -- .../adapter/channel/PullMessageChannel.java | 29 ---------- .../handler/PullMessageResponseHandler.java | 57 ------------------- .../grpc/v2/service/LocalGrpcService.java | 15 ----- 4 files changed, 105 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index add450e5a1..304d23e9ec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -24,9 +24,7 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.PullMessageRequest; import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryOffsetRequest; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.SendMessageRequest; @@ -47,8 +45,6 @@ public class RequestMapping { put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); - put(PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java deleted file mode 100644 index d65c74aba9..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/PullMessageChannel.java +++ /dev/null @@ -1,29 +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.proxy.grpc.v2.adapter.channel; - -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; -import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.PullMessageResponseHandler; - -public class PullMessageChannel extends InvocationChannel { - public PullMessageChannel(PullMessageResponseHandler handler) { - super(handler); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.java deleted file mode 100644 index d4e351121a..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/PullMessageResponseHandler.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.proxy.grpc.v2.adapter.handler; - -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; -import java.nio.ByteBuffer; -import java.util.List; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class PullMessageResponseHandler implements ResponseHandler { - @Override - public void handle(RemotingCommand responseCommand, - InvocationContext context) { - try { - PullMessageResponseHeader responseHeader = (PullMessageResponseHeader) responseCommand.readCustomHeader(); - PullMessageResponse.Builder builder = PullMessageResponse.newBuilder(); - if (responseCommand.getCode() == ResponseCode.SUCCESS) { - ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); - List msgFoundList = MessageDecoder.decodes(byteBuffer); - for (MessageExt messageExt : msgFoundList) { - builder.addMessages(GrpcConverter.buildMessage(messageExt)); - } - } - PullMessageResponse response = builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .setMinOffset(responseHeader.getMinOffset()) - .setNextOffset(responseHeader.getNextBeginOffset()) - .setMaxOffset(responseHeader.getMaxOffset()) - .build(); - context.getResponse().complete(response); - } catch (Exception e) { - context.getResponse().completeExceptionally(e); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index bca408ee58..fe42e56c1d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -21,10 +21,7 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ClientOverwrittenSettings; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Direction; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -35,14 +32,8 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.Publishing; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryOffsetPolicy; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -50,12 +41,9 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; -import com.google.protobuf.util.Timestamps; import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; @@ -86,7 +74,6 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHea import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; @@ -105,10 +92,8 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.PullMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.PullMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; From af93b97453a2c3d9a8561880bd9c5be55ee8674a Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 21 Apr 2022 18:00:42 +0800 Subject: [PATCH 108/338] [ISSUE #3949] v2 test cases --- .../test/grpc/v2/ClusterGrpcTest.java | 5 - .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 188 ++++++------------ .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 5 - 3 files changed, 56 insertions(+), 142 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 680f8a1e2c..cab6068a61 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -91,9 +91,4 @@ public class ClusterGrpcTest extends GrpcBaseTest { public void testSendReceiveMessageThenToDLQ() throws Exception { super.testSendReceiveMessageThenToDLQ(); } - - @Test - public void testPullMessage() throws Exception { - super.testPullMessage(); - } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 0415d6dbd1..a911fb5653 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -17,16 +17,16 @@ package org.apache.rocketmq.test.grpc.v2; +import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ActivePublishingSettings; +import apache.rocketmq.v2.ActiveSubscriptionSettings; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.ClientOverwrittenSettings; -import apache.rocketmq.v2.ClientSettings; +import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.DeadLetterPolicy; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.Endpoints; @@ -37,24 +37,17 @@ import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; -import apache.rocketmq.v2.Publishing; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryOffsetPolicy; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.TransactionResolution; @@ -80,7 +73,9 @@ import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.IOException; import java.net.URL; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -101,7 +96,6 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; -import org.junit.Test; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; @@ -137,6 +131,7 @@ public class GrpcBaseTest extends BaseConf { ConfigurationManager.intConfig(); ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(2); blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); @@ -152,19 +147,20 @@ public class GrpcBaseTest extends BaseConf { return MetadataUtils.attachHeaders(stub, header); } - protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, ClientSettings clientSettings) { - CompletableFuture future = new CompletableFuture<>(); + protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, + ReportActiveSettingsCommand clientSettings) { + CompletableFuture future = new CompletableFuture<>(); StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { @Override public void onNext(TelemetryCommand value) { TelemetryCommand.CommandCase commandCase = value.getCommandCase(); - if (TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS.equals(commandCase)) { - future.complete(value.getClientOverwrittenSettings()); + if (TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND.equals(commandCase)) { + future.complete(value.getApplyPassiveSettingsCommand()); } } }); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(clientSettings) + .setReportActiveSettingsCommand(clientSettings) .build()); requestStreamObserver.onCompleted(); return future; @@ -207,7 +203,7 @@ public class GrpcBaseTest extends BaseConf { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; - this.sendClientSettings(stub, ClientSettings.newBuilder() + this.sendClientSettings(stub, ReportActiveSettingsCommand.newBuilder() .setNonce(UUID.randomUUID().toString()) .setClientType(ClientType.PRODUCER) .build()) @@ -222,19 +218,16 @@ public class GrpcBaseTest extends BaseConf { this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group); + ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(response, messageId); String receiptHandle = response.getMessages(0).getSystemProperties().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, receiptHandle)); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, messageId, receiptHandle)); assertAck(ackMessageResponse); } public void testSendReceiveMessageThenToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - this.sendClientSettings(stub, ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PRODUCER) - .build()) + this.sendClientSettings(stub, buildProducerClientSettings(topic)) .get(); String group = "group"; @@ -248,7 +241,7 @@ public class GrpcBaseTest extends BaseConf { this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group); + ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(receiveResponse, messageId); Message message = receiveResponse.getMessages(0); @@ -259,7 +252,7 @@ public class GrpcBaseTest extends BaseConf { AtomicReference receiveRetryResponseRef = new AtomicReference<>(); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group, 1); + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group, 1).get(0); if (receiveRetryResponse.getMessagesCount() <= 0) { return false; } @@ -291,7 +284,6 @@ public class GrpcBaseTest extends BaseConf { }); } - @Test public void testTransactionCheckThenCommit() { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; @@ -306,13 +298,13 @@ public class GrpcBaseTest extends BaseConf { try { requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(buildPushConsumerClientSettings()) + .setReportActiveSettingsCommand(buildPushConsumerClientSettings()) .build()); await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { if (telemetryCommandRef.get() == null) { return false; } - if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS) { + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND) { return false; } return telemetryCommandRef.get() != null; @@ -322,7 +314,7 @@ public class GrpcBaseTest extends BaseConf { receiveMessage(blockingStub, topic, group); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(buildProducerClientSettings(topic)) + .setReportActiveSettingsCommand(buildProducerClientSettings(topic)) .build()); blockingStub.heartbeat(HeartbeatRequest.newBuilder() .setGroup(Resource.newBuilder() @@ -333,7 +325,7 @@ public class GrpcBaseTest extends BaseConf { if (telemetryCommandRef.get() == null) { return false; } - if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.CLIENT_OVERWRITTEN_SETTINGS) { + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND) { return false; } return telemetryCommandRef.get() != null; @@ -361,11 +353,11 @@ public class GrpcBaseTest extends BaseConf { assertEndTransactionResponse(endTransactionResponse); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(buildPushConsumerClientSettings()) + .setReportActiveSettingsCommand(buildPushConsumerClientSettings()) .build()); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group); + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); if (receiveRetryResponse.getMessagesCount() <= 0) { return false; } @@ -377,40 +369,24 @@ public class GrpcBaseTest extends BaseConf { } } - public void testPullMessage() throws Exception { - String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = "group"; - String messageId = createUniqID(); - - this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); - assertSendMessage(blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)), messageId); - - this.sendClientSettings(stub, buildPullConsumerClientSettings()).get(); - - QueryOffsetResponse queryOffsetResponse = blockingStub.queryOffset(buildQueryOffsetRequest(broker1Name, topic, QueryOffsetPolicy.BEGINNING)); - assertQueryOffsetResponse(queryOffsetResponse, 0L); - - queryOffsetResponse = blockingStub.queryOffset(buildQueryOffsetRequest(broker1Name, topic, QueryOffsetPolicy.END)); - assertQueryOffsetResponse(queryOffsetResponse, 1L); - - await().atMost(java.time.Duration.ofSeconds(10)).until(() -> { - PullMessageResponse response = blockingStub.withDeadlineAfter(20, TimeUnit.SECONDS) - .pullMessage(buildPullMessageRequest(broker1Name, group, topic, 0L)); - if (response.getMessagesCount() <= 0) { - return false; - } - return response.getMessages(0).getSystemProperties().getMessageId().equals(messageId); - }); + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { + List responseList = new ArrayList<>(); + Iterator responseIterator = stub.withDeadlineAfter(15, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(group, topic)); + while (responseIterator.hasNext()) { + responseList.add(responseIterator.next()); + } + return responseList; } - public ReceiveMessageResponse receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { - return stub.withDeadlineAfter(15, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); - } - - public ReceiveMessageResponse receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group, int timeSeconds) { - return stub.withDeadlineAfter(timeSeconds, TimeUnit.SECONDS) + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group, int timeSeconds) { + List responseList = new ArrayList<>(); + Iterator responseIterator = stub.withDeadlineAfter(timeSeconds, TimeUnit.SECONDS) .receiveMessage(buildReceiveMessageRequest(group, topic)); + while (responseIterator.hasNext()) { + responseList.add(responseIterator.next()); + } + return responseList; } public QueryRouteRequest buildQueryRouteRequest(String topic) { @@ -493,7 +469,7 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public AckMessageRequest buildAckMessageRequest(String group, String topic, String receiptHandle) { + public AckMessageRequest buildAckMessageRequest(String group, String topic, String messageId, String receiptHandle) { return AckMessageRequest.newBuilder() .setGroup(Resource.newBuilder() .setName(group) @@ -501,7 +477,10 @@ public class GrpcBaseTest extends BaseConf { .setTopic(Resource.newBuilder() .setName(topic) .build()) - .setReceiptHandle(receiptHandle) + .addEntries(AckMessageEntry.newBuilder() + .setMessageId(messageId) + .setReceiptHandle(receiptHandle) + .build()) .build(); } @@ -532,30 +511,6 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public QueryOffsetRequest buildQueryOffsetRequest(String brokerName, String topic, QueryOffsetPolicy queryOffsetPolicy) { - return QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder().setName(topic).build()) - .setBroker(Broker.newBuilder().setName(brokerName).build()) - .setId(0) - .build()) - .setPolicy(queryOffsetPolicy) - .build(); - } - - public PullMessageRequest buildPullMessageRequest(String brokerName, String group, String topic, long offset) { - return PullMessageRequest.newBuilder() - .setGroup(Resource.newBuilder().setName(group).build()) - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder().setName(topic).build()) - .setBroker(Broker.newBuilder().setName(brokerName).build()) - .setId(0) - .build()) - .setBatchSize(32) - .setOffset(offset) - .build(); - } - public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); @@ -602,13 +557,8 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); } - public void assertQueryOffsetResponse(QueryOffsetResponse response, long offset) { - assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(response.getOffset()).isEqualTo(offset); - } - - public ClientSettings buildAccessPointClientSettings(int port) { - return ClientSettings.newBuilder() + public ReportActiveSettingsCommand buildAccessPointClientSettings(int port) { + return ReportActiveSettingsCommand.newBuilder() .setNonce(UUID.randomUUID().toString()) .setAccessPoint(Endpoints.newBuilder() .setScheme(AddressScheme.IPv4) @@ -620,53 +570,27 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public ClientSettings buildPushConsumerClientSettings() { + public ReportActiveSettingsCommand buildPushConsumerClientSettings() { return buildPushConsumerClientSettings(2, false); } - public ClientSettings buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { - return ClientSettings.newBuilder() + public ReportActiveSettingsCommand buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + return ReportActiveSettingsCommand.newBuilder() .setNonce(UUID.randomUUID().toString()) .setClientType(ClientType.PUSH_CONSUMER) - .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() - .setMaxDeliveryAttempts(maxDeliveryAttempts) - .build()) - .setFifo(fifo) - .build()) + .setActiveSubscriptionSettings(ActiveSubscriptionSettings.newBuilder() .build()) .build(); } - public ClientSettings buildPullConsumerClientSettings() { - return ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PULL_CONSUMER) - .setSettings(Settings.newBuilder() - .build()) - .build(); - } - - public ClientSettings buildSimpleConsumerClientSettings() { - return ClientSettings.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.SIMPLE_CONSUMER) - .setSettings(Settings.newBuilder() - .build()) - .build(); - } - - public ClientSettings buildProducerClientSettings(String... topics) { + public ReportActiveSettingsCommand buildProducerClientSettings(String... topics) { List topicResources = Arrays.stream(topics).map(topic -> Resource.newBuilder().setName(topic).build()) .collect(Collectors.toList()); - return ClientSettings.newBuilder() + return ReportActiveSettingsCommand.newBuilder() .setNonce(UUID.randomUUID().toString()) .setClientType(ClientType.PRODUCER) - .setSettings(Settings.newBuilder() - .setPublishing(Publishing.newBuilder() - .addAllTopics(topicResources) - .build()) + .setActivePublishingSettings(ActivePublishingSettings.newBuilder() + .addAllPublishingTopics(topicResources) .build()) .build(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index cf5023755a..282fff469b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -66,9 +66,4 @@ public class LocalGrpcTest extends GrpcBaseTest { public void testSendReceiveMessageThenToDLQ() throws Exception { super.testSendReceiveMessageThenToDLQ(); } - - @Test - public void testPullMessage() throws Exception { - super.testPullMessage(); - } } From 9b8e49bc88d33403a79eca8841f05e7b2a9e11e2 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 10:25:06 +0800 Subject: [PATCH 109/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/adapter/GrpcConverter.java | 42 ++---------- ...ervice.java => ClientSettingsService.java} | 34 +++------- .../grpc/v2/service/GrpcClientManager.java | 67 +++---------------- .../grpc/v2/service/LocalGrpcService.java | 18 ++--- .../service/cluster/ForwardClientService.java | 26 +++---- .../grpc/v2/service/cluster/RouteService.java | 5 +- .../cluster/ForwardClientServiceTest.java | 31 +++++---- .../v2/service/cluster/RouteServiceTest.java | 14 ++-- 8 files changed, 69 insertions(+), 168 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/{ReportActiveSettingsService.java => ClientSettingsService.java} (61%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index cbb5bb6dcd..6da864d1b6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; @@ -26,7 +25,6 @@ import apache.rocketmq.v2.Digest; import apache.rocketmq.v2.DigestType; import apache.rocketmq.v2.Encoding; import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -36,11 +34,10 @@ import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.PassivePublishingSettings; -import apache.rocketmq.v2.PassiveSubscriptionSettings; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.SubscriptionEntry; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TransactionResolution; @@ -91,9 +88,7 @@ import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,20 +100,19 @@ public class GrpcConverter { } public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, - GrpcClientManager.ActiveClientSettings clientSettings) { + Settings clientSettings) { HeartbeatData heartbeatData = new HeartbeatData(); heartbeatData.setClientID(clientId); switch (clientSettings.getClientType()) { case PRODUCER: { Set producerDataSet = new HashSet<>(); - for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { String topicName = wrapResourceWithNamespace(topic); producerDataSet.add(buildProducerData(topicName)); } heartbeatData.setProducerDataSet(producerDataSet); break; } - case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { String groupName = wrapResourceWithNamespace(request.getGroup()); @@ -139,7 +133,7 @@ public class GrpcConverter { } public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, - GrpcClientManager.ActiveClientSettings clientSettings) { + Settings clientSettings) { org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); buildConsumerData.setGroupName(groupName); buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); @@ -147,14 +141,13 @@ public class GrpcConverter { buildConsumerData.setMessageModel(MessageModel.CLUSTERING); buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); Set subscriptionDataSet = - buildSubscriptionDataSet(clientSettings.getActiveSubscriptionSettings().getSubscriptionsList()); + buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()); buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); return buildConsumerData; } public static ConsumeType buildConsumeType(ClientType clientType) { switch (clientType) { - case PULL_CONSUMER: case SIMPLE_CONSUMER: return ConsumeType.CONSUME_ACTIVELY; case PUSH_CONSUMER: @@ -369,7 +362,6 @@ public class GrpcConverter { header.setProducerGroup(groupName); break; } - case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { header.setConsumerGroup(groupName); @@ -508,30 +500,6 @@ public class GrpcConverter { .build(); } - public static ApplyPassiveSettingsCommand buildDefaultPublishingSettings(String nonce, Endpoints traceEndpoint) { - ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - return ApplyPassiveSettingsCommand.newBuilder() - .setNonce(nonce) - .setTraceAccessPoint(traceEndpoint) - .setPassivePublishingSettings(PassivePublishingSettings.newBuilder() - .setMaxMessageBodyBytes(proxyConfig.getMaxMessageBodyBytes()) - .setMessageBodyCompressionBytesThreshold(proxyConfig.getDefaultMessageBodyCompressionBytesThreshold()) - .setOrphanedTransactionRecoveryDuration(Durations.fromSeconds(proxyConfig.getDefaultTransactionRecoverySecond())) - .build()) - .build(); - } - - public static ApplyPassiveSettingsCommand buildDefaultSubscriptionSettings(String nonce, Endpoints traceEndpoint) { - // TODO: read config from subscriptionGroupManager - return ApplyPassiveSettingsCommand.newBuilder() - .setNonce(nonce) - .setTraceAccessPoint(traceEndpoint) - .setPassiveSubscriptionSettings(PassiveSubscriptionSettings.newBuilder() - .setFifo(false) - .build()) - .build(); - } - protected static Map buildUserAttributes(MessageExt messageExt) { Map userAttributes = new HashMap<>(); Map properties = messageExt.getProperties(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java similarity index 61% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java index 6a771fcd0c..40897b4ea6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReportActiveSettingsService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java @@ -17,10 +17,8 @@ package org.apache.rocketmq.proxy.grpc.v2.service; -import apache.rocketmq.v2.ActiveSubscriptionSettings; -import apache.rocketmq.v2.ApplyPassiveSettingsCommand; -import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; @@ -30,13 +28,13 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -public class ReportActiveSettingsService { +public class ClientSettingsService { private final ChannelManager channelManager; private final GrpcClientManager grpcClientManager; private final TelemetryCommandManager telemetryCommandManager; - public ReportActiveSettingsService(ChannelManager channelManager, + public ClientSettingsService(ChannelManager channelManager, GrpcClientManager grpcClientManager, TelemetryCommandManager telemetryCommandManager) { this.channelManager = channelManager; @@ -44,34 +42,24 @@ public class ReportActiveSettingsService { this.telemetryCommandManager = telemetryCommandManager; } - public TelemetryCommand processReportActiveSettingsCommand(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { + public TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - ReportActiveSettingsCommand reportActiveSettings = request.getReportActiveSettingsCommand(); - grpcClientManager.updateClientSettings(clientId, reportActiveSettings); - ApplyPassiveSettingsCommand applyPassiveSettingsCommand = ApplyPassiveSettingsCommand.getDefaultInstance(); - if (reportActiveSettings.hasActivePublishingSettings()) { - for (Resource topic : reportActiveSettings.getActivePublishingSettings().getPublishingTopicsList()) { + grpcClientManager.updateClientSettings(clientId, request.getSettings()); + Settings settings = grpcClientManager.getClientSettings(clientId); + if (settings.hasPublishing()) { + for (Resource topic : settings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); producerChannel.setClientObserver(responseObserver); } - applyPassiveSettingsCommand = GrpcConverter.buildDefaultPublishingSettings( - reportActiveSettings.getNonce(), - reportActiveSettings.getAccessPoint() - ); } - if (reportActiveSettings.hasActiveSubscriptionSettings()) { - ActiveSubscriptionSettings subscription = reportActiveSettings.getActiveSubscriptionSettings(); - String groupName = GrpcConverter.wrapResourceWithNamespace(subscription.getGroup()); + if (settings.hasSubscription()) { + String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); consumerChannel.setClientObserver(responseObserver); - applyPassiveSettingsCommand = GrpcConverter.buildDefaultSubscriptionSettings( - reportActiveSettings.getNonce(), - reportActiveSettings.getAccessPoint() - ); } return TelemetryCommand.newBuilder() - .setApplyPassiveSettingsCommand(applyPassiveSettingsCommand) + .setSettings(settings) .build(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index 3042735a04..2a93676e7b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -17,81 +17,30 @@ package org.apache.rocketmq.proxy.grpc.v2.service; -import apache.rocketmq.v2.ActivePublishingSettings; -import apache.rocketmq.v2.ActiveSubscriptionSettings; -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.ReportActiveSettingsCommand; -import com.google.protobuf.Duration; +import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { + + private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); - public static class ActiveClientSettings { - private ClientType clientType; - private Endpoints accessPoint; - private Duration connectionTimeout; - private boolean traceOn = true; - private ActivePublishingSettings activePublishingSettings; - private ActiveSubscriptionSettings activeSubscriptionSettings; - - public ActiveClientSettings(ReportActiveSettingsCommand reportActiveSettingsCommand) { - this.clientType = reportActiveSettingsCommand.getClientType(); - this.accessPoint = reportActiveSettingsCommand.getAccessPoint(); - this.connectionTimeout = reportActiveSettingsCommand.getConnectionTimeout(); - this.traceOn = reportActiveSettingsCommand.getTraceOn(); - if (reportActiveSettingsCommand.hasActivePublishingSettings()) { - this.activePublishingSettings = reportActiveSettingsCommand.getActivePublishingSettings(); - } - if (reportActiveSettingsCommand.hasActiveSubscriptionSettings()) { - this.activeSubscriptionSettings = reportActiveSettingsCommand.getActiveSubscriptionSettings(); - } - } - - public ClientType getClientType() { - return clientType; - } - - public Endpoints getAccessPoint() { - return accessPoint; - } - - public Duration getConnectionTimeout() { - return connectionTimeout; - } - - public boolean isTraceOn() { - return traceOn; - } - - public ActivePublishingSettings getActivePublishingSettings() { - return activePublishingSettings; - } - - public ActiveSubscriptionSettings getActiveSubscriptionSettings() { - return activeSubscriptionSettings; - } - } - - private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); - - public ActiveClientSettings getClientSettings(Context ctx) { + public Settings getClientSettings(Context ctx) { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); return CLIENT_SETTINGS_MAP.get(clientId); } - public ActiveClientSettings getClientSettings(String clientId) { + public Settings getClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.get(clientId); } - public void updateClientSettings(String clientId, ReportActiveSettingsCommand reportActiveSettingsCommand) { - CLIENT_SETTINGS_MAP.put(clientId, new ActiveClientSettings(reportActiveSettingsCommand)); + public void updateClientSettings(String clientId, Settings settings) { + CLIENT_SETTINGS_MAP.put(clientId, settings); } - public ActiveClientSettings removeClientSettings(String clientId) { + public Settings removeClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.remove(clientId); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index fe42e56c1d..901e6d4989 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -41,6 +41,7 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; @@ -114,7 +115,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final TelemetryCommandManager telemetryCommandManager; private final GrpcClientManager grpcClientManager; private final RouteService routeService; - private final ReportActiveSettingsService reportActiveSettingsService; + private final ClientSettingsService clientSettingsService; private final DelayPolicy delayPolicy; public LocalGrpcService(BrokerController brokerController) { @@ -134,7 +135,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.telemetryCommandManager = telemetryCommandManager; this.grpcClientManager = new GrpcClientManager(); this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); - this.reportActiveSettingsService = new ReportActiveSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); + this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); @@ -155,7 +156,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); languageCode = LanguageCode.valueOf(language); - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + Settings clientSettings = grpcClientManager.getClientSettings(clientId); HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); command.setLanguage(languageCode); @@ -166,7 +167,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo CompletableFuture future = new CompletableFuture<>(); switch (clientSettings.getClientType()) { case PRODUCER: { - for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); @@ -180,7 +181,6 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo future.complete(heartbeatResponse); break; } - case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); @@ -286,7 +286,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request); + AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, null); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); @@ -447,7 +447,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + Settings clientSettings = grpcClientManager.getClientSettings(clientId); UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); @@ -506,8 +506,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public void onNext(TelemetryCommand request) { switch (request.getCommandCase()) { - case REPORT_ACTIVE_SETTINGS_COMMAND: { - responseObserver.onNext(reportActiveSettingsService.processReportActiveSettingsCommand(ctx, request, responseObserver)); + case SETTINGS: { + responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); break; } case THREAD_STACK_TRACE: { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index b25a3f4934..1124685d32 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -16,15 +16,13 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.ActiveSubscriptionSettings; -import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; @@ -51,7 +49,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.ReportActiveSettingsService; +import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,7 +62,7 @@ public class ForwardClientService extends BaseService { private final ProducerManager producerManager; private final GrpcClientManager grpcClientManager; private final TelemetryCommandManager telemetryCommandManager; - private final ReportActiveSettingsService reportActiveSettingsService; + private final ClientSettingsService clientSettingsService; public ForwardClientService( ConnectorManager connectorManager, @@ -83,7 +81,7 @@ public class ForwardClientService extends BaseService { this.grpcClientManager = grpcClientManager; this.telemetryCommandManager = telemetryCommandManager; - this.reportActiveSettingsService = new ReportActiveSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); + this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); this.producerManager = new ProducerManager(); @@ -138,10 +136,10 @@ public class ForwardClientService extends BaseService { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); LanguageCode languageCode = LanguageCode.valueOf(language); - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + Settings clientSettings = grpcClientManager.getClientSettings(clientId); switch (clientSettings.getClientType()) { case PRODUCER: { - for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -151,7 +149,6 @@ public class ForwardClientService extends BaseService { } break; } - case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: { if (!request.hasGroup()) { @@ -167,7 +164,7 @@ public class ForwardClientService extends BaseService { GrpcConverter.buildConsumeType(clientSettings.getClientType()), MessageModel.CLUSTERING, ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, - GrpcConverter.buildSubscriptionDataSet(clientSettings.getActiveSubscriptionSettings().getSubscriptionsList()), + GrpcConverter.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()), false ); break; @@ -191,11 +188,11 @@ public class ForwardClientService extends BaseService { try { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(clientId); + Settings clientSettings = grpcClientManager.getClientSettings(clientId); switch (clientSettings.getClientType()) { case PRODUCER: - for (Resource topic : clientSettings.getActivePublishingSettings().getPublishingTopicsList()) { + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); // user topic name as producer group GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); @@ -204,7 +201,6 @@ public class ForwardClientService extends BaseService { } } break; - case PULL_CONSUMER: case PUSH_CONSUMER: case SIMPLE_CONSUMER: if (!request.hasGroup()) { @@ -232,8 +228,8 @@ public class ForwardClientService extends BaseService { return new StreamObserver() { @Override public void onNext(TelemetryCommand request) { - if (request.getCommandCase() == TelemetryCommand.CommandCase.REPORT_ACTIVE_SETTINGS_COMMAND) { - responseObserver.onNext(reportActiveSettingsService.processReportActiveSettingsCommand(ctx, request, responseObserver)); + if (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) { + responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index 04619890f3..a4db99b3a6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -29,6 +29,7 @@ import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; import com.google.common.base.Preconditions; import com.google.common.net.HostAndPort; import io.grpc.Context; @@ -112,7 +113,7 @@ public class RouteService extends BaseService { List messageQueueList = new ArrayList<>(); if (ProxyMode.isClusterMode(mode.name())) { - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); + Settings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() @@ -243,7 +244,7 @@ public class RouteService extends BaseService { } } if (ProxyMode.isClusterMode(mode)) { - GrpcClientManager.ActiveClientSettings clientSettings = grpcClientManager.getClientSettings(ctx); + Settings clientSettings = grpcClientManager.getClientSettings(ctx); Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index 21a37ef5de..8ea04fe051 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -1,14 +1,14 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.ActivePublishingSettings; -import apache.rocketmq.v2.ActiveSubscriptionSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.ReportActiveSettingsCommand; +import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SubscriptionEntry; import io.grpc.Context; import io.netty.channel.Channel; @@ -23,7 +23,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.junit.Test; @@ -52,17 +51,17 @@ public class ForwardClientServiceTest extends BaseServiceTest { @Test public void testProducerHeartbeat() { - GrpcClientManager.ActiveClientSettings clientSettings = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + Settings clientSettings = Settings.newBuilder() .setClientType(ClientType.PRODUCER) - .setActivePublishingSettings(ActivePublishingSettings.newBuilder() - .addPublishingTopics(Resource.newBuilder() - .setName("topic1") + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder() + .setName("topic1") + .build()) + .addTopics(Resource.newBuilder() + .setName("topic2") + .build()) .build()) - .addPublishingTopics(Resource.newBuilder() - .setName("topic2") - .build()) - .build()) - .build()); + .build(); when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); @@ -89,12 +88,12 @@ public class ForwardClientServiceTest extends BaseServiceTest { .build()) .build()); - GrpcClientManager.ActiveClientSettings clientSettings = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + Settings clientSettings = Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) - .setActiveSubscriptionSettings(ActiveSubscriptionSettings.newBuilder() + .setSubscription(Subscription.newBuilder() .addAllSubscriptions(subscriptionEntryList) .build()) - .build()); + .build(); when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 44963565e6..acd0505c53 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -30,6 +30,7 @@ import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; import com.google.common.net.HostAndPort; import io.grpc.Context; import java.util.ArrayList; @@ -63,15 +64,14 @@ public class RouteServiceTest extends BaseServiceTest { .setResourceNamespace(NAMESPACE) .build(); - private static final GrpcClientManager.ActiveClientSettings WITH_HOST_SETTINGS = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") .build()) - .buildPartial()); + .setScheme(AddressScheme.DOMAIN_NAME) + .build()); private static final GrpcClientManager.ActiveClientSettings INVALID_HOST_SETTINGS = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() .setAccessPoint(Endpoints.getDefaultInstance()) From 8caa00cdc18395d4dabda11cc50101231aa6b284 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 22 Apr 2022 10:53:58 +0800 Subject: [PATCH 110/338] [ISSUE #3949] use the right exception. --- .../connector/transaction/TransactionId.java | 18 ++++++++---- .../ReceiveMessageResponseHandler.java | 29 ++++++++++++------- .../handler/SendMessageResponseHandler.java | 19 ++++++++---- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index 4a4b176cbc..e0d5a4ee20 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -74,8 +74,12 @@ public class TransactionId { commitLogOffset, sendResult.getQueueOffset()); } - public static TransactionId genByBrokerTransactionId(SocketAddress brokerAddr, String orgTransactionId, - long commitLogOffset, long tranStateTableOffset) { + public static TransactionId genByBrokerTransactionId( + SocketAddress brokerAddr, + String orgTransactionId, + long commitLogOffset, + long tranStateTableOffset + ) { byte[] orgTransactionIdByte = new byte[0]; if (StringUtils.isNotBlank(orgTransactionId)) { orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); @@ -127,9 +131,13 @@ public class TransactionId { .build(); } - public static long generateCommitLogOffset(String messageId) throws UnknownHostException { - MessageId id = MessageDecoder.decodeMessageId(messageId); - return id.getOffset(); + public static long generateCommitLogOffset(String messageId) throws IllegalArgumentException { + try { + MessageId id = MessageDecoder.decodeMessageId(messageId); + return id.getOffset(); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("illegal messageId: " + messageId); + } } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 6d076490f4..8b54b8b80f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -96,10 +96,14 @@ public class ReceiveMessageResponseHandler implements ResponseHandler { + private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); private final String messageId; private final int sysFlag; private final String localAddress; @@ -42,7 +45,8 @@ public class SendMessageResponseHandler implements ResponseHandler context) { // If responseCommand equals to null, then the response has been written to channel. // org.apache.rocketmq.broker.processor.SendMessageProcessor#handlePutMessageResult @@ -55,11 +59,16 @@ public class SendMessageResponseHandler implements ResponseHandler Date: Fri, 22 Apr 2022 10:46:23 +0800 Subject: [PATCH 111/338] [ISSUE #3949] v2 support --- .../rocketmq/proxy/config/ProxyConfig.java | 37 ---------- .../v2/service/cluster/ConsumerService.java | 8 ++- .../service/cluster/ConsumerServiceTest.java | 30 ++++++-- .../v2/service/cluster/RouteServiceTest.java | 9 ++- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 68 +++++++++---------- 5 files changed, 67 insertions(+), 85 deletions(-) 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 e108f8de3a..a5da3cdae0 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 @@ -57,11 +57,6 @@ public class ProxyConfig { */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; - private int maxMessageBodyBytes = 1024 * 1024 * 4; - private int defaultMessageBodyCompressionBytesThreshold = 1024 * 4; - private int defaultTransactionRecoverySecond = 30; - private int defaultMaxDeliveryAttempts = 16; - private int channelExpiredInSeconds = 60; private int forwardConsumerNum = 2; @@ -242,38 +237,6 @@ public class ProxyConfig { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } - public int getMaxMessageBodyBytes() { - return maxMessageBodyBytes; - } - - public void setMaxMessageBodyBytes(int maxMessageBodyBytes) { - this.maxMessageBodyBytes = maxMessageBodyBytes; - } - - public int getDefaultMessageBodyCompressionBytesThreshold() { - return defaultMessageBodyCompressionBytesThreshold; - } - - public void setDefaultMessageBodyCompressionBytesThreshold(int defaultMessageBodyCompressionBytesThreshold) { - this.defaultMessageBodyCompressionBytesThreshold = defaultMessageBodyCompressionBytesThreshold; - } - - public int getDefaultTransactionRecoverySecond() { - return defaultTransactionRecoverySecond; - } - - public void setDefaultTransactionRecoverySecond(int defaultTransactionRecoverySecond) { - this.defaultTransactionRecoverySecond = defaultTransactionRecoverySecond; - } - - public int getDefaultMaxDeliveryAttempts() { - return defaultMaxDeliveryAttempts; - } - - public void setDefaultMaxDeliveryAttempts(int defaultMaxDeliveryAttempts) { - this.defaultMaxDeliveryAttempts = defaultMaxDeliveryAttempts; - } - public int getChannelExpiredInSeconds() { return channelExpiredInSeconds; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index c9d2fceebc..dfb43d89a8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -28,6 +28,7 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; import java.util.List; @@ -131,8 +132,8 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - // TODO: get fifo config from subscriptionGroupManager - return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), false); + boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); + return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { @@ -289,7 +290,8 @@ public class ConsumerService extends BaseService { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - int maxDeliveryAttempts = ConfigurationManager.getProxyConfig().getDefaultMaxDeliveryAttempts(); + Settings settings = grpcClientManager.getClientSettings(ctx); + int maxDeliveryAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { CompletableFuture resultFuture = this.producer.sendMessageBack( brokerAddr, diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 5a37e6a910..a866e11aaa 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -11,6 +11,9 @@ import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -60,6 +63,13 @@ public class ConsumerServiceTest extends BaseServiceTest { new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); + Settings clientSettings = Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setFifo(false) + .build()) + .build(); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + List messageExtList = Lists.newArrayList( createMessageExt("msg1", "msg1"), createMessageExt("msg2", "msg2") @@ -113,7 +123,7 @@ public class ConsumerServiceTest extends BaseServiceTest { .setMessageId("msgId") .setReceiptHandle(createReceiptHandle().encode())) .build()) - .get(); + .get(); assertEquals(Code.OK, response.getStatus().getCode()); } @@ -128,7 +138,8 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(producerClient).sendMessageBack(anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(3); + Settings clientSettings = createClientSettings(3); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -140,7 +151,7 @@ public class ConsumerServiceTest extends BaseServiceTest { .setReceiptHandle(receiptHandle.encode()) .setDeliveryAttempt(3) .build()) - .get(); + .get(); assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(receiptHandle.getCommitLogOffset(), headerRef.get().getOffset().longValue()); @@ -158,7 +169,8 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(3); + Settings clientSettings = createClientSettings(3); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -176,4 +188,14 @@ public class ConsumerServiceTest extends BaseServiceTest { assertEquals(receiptHandle.getOffset(), headerRef.get().getOffset().longValue()); assertEquals(receiptHandle.encode(), headerRef.get().getExtraInfo()); } + + private Settings createClientSettings(int maxDeliveryAttempts) { + return Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) + .build()) + .build(); + } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index acd0505c53..4d9cb69bce 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -28,7 +28,6 @@ import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; import com.google.common.net.HostAndPort; @@ -45,7 +44,6 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -71,11 +69,12 @@ public class RouteServiceTest extends BaseServiceTest { .setHost("host") .build()) .setScheme(AddressScheme.DOMAIN_NAME) - .build()); + .build()) + .build(); - private static final GrpcClientManager.ActiveClientSettings INVALID_HOST_SETTINGS = new GrpcClientManager.ActiveClientSettings(ReportActiveSettingsCommand.newBuilder() + private static final Settings INVALID_HOST_SETTINGS = Settings.newBuilder() .setAccessPoint(Endpoints.getDefaultInstance()) - .buildPartial()); + .build(); @Override public void beforeEach() throws Exception { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index a911fb5653..783ecbed4e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -20,11 +20,8 @@ package org.apache.rocketmq.test.grpc.v2; import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ActivePublishingSettings; -import apache.rocketmq.v2.ActiveSubscriptionSettings; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.ApplyPassiveSettingsCommand; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; @@ -37,6 +34,7 @@ import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.MessagingServiceGrpc; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; +import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; @@ -44,10 +42,12 @@ import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -import apache.rocketmq.v2.ReportActiveSettingsCommand; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.TransactionResolution; @@ -96,6 +96,7 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; +import org.junit.Test; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; @@ -131,7 +132,6 @@ public class GrpcBaseTest extends BaseConf { ConfigurationManager.intConfig(); ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); - ConfigurationManager.getProxyConfig().setDefaultMaxDeliveryAttempts(2); blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); @@ -147,20 +147,19 @@ public class GrpcBaseTest extends BaseConf { return MetadataUtils.attachHeaders(stub, header); } - protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, - ReportActiveSettingsCommand clientSettings) { - CompletableFuture future = new CompletableFuture<>(); + protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, Settings clientSettings) { + CompletableFuture future = new CompletableFuture<>(); StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { @Override public void onNext(TelemetryCommand value) { TelemetryCommand.CommandCase commandCase = value.getCommandCase(); - if (TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND.equals(commandCase)) { - future.complete(value.getApplyPassiveSettingsCommand()); + if (TelemetryCommand.CommandCase.SETTINGS.equals(commandCase)) { + future.complete(value.getSettings()); } } }); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setReportActiveSettingsCommand(clientSettings) + .setSettings(clientSettings) .build()); requestStreamObserver.onCompleted(); return future; @@ -203,11 +202,7 @@ public class GrpcBaseTest extends BaseConf { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; - this.sendClientSettings(stub, ReportActiveSettingsCommand.newBuilder() - .setNonce(UUID.randomUUID().toString()) - .setClientType(ClientType.PRODUCER) - .build()) - .get(); + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); // init consumer offset receiveMessage(blockingStub, topic, group); @@ -227,8 +222,7 @@ public class GrpcBaseTest extends BaseConf { public void testSendReceiveMessageThenToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - this.sendClientSettings(stub, buildProducerClientSettings(topic)) - .get(); + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); String group = "group"; @@ -284,6 +278,7 @@ public class GrpcBaseTest extends BaseConf { }); } + @Test public void testTransactionCheckThenCommit() { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; @@ -298,13 +293,13 @@ public class GrpcBaseTest extends BaseConf { try { requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setReportActiveSettingsCommand(buildPushConsumerClientSettings()) + .setSettings(buildPushConsumerClientSettings()) .build()); await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { if (telemetryCommandRef.get() == null) { return false; } - if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND) { + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.SETTINGS) { return false; } return telemetryCommandRef.get() != null; @@ -314,7 +309,7 @@ public class GrpcBaseTest extends BaseConf { receiveMessage(blockingStub, topic, group); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setReportActiveSettingsCommand(buildProducerClientSettings(topic)) + .setSettings(buildProducerClientSettings(topic)) .build()); blockingStub.heartbeat(HeartbeatRequest.newBuilder() .setGroup(Resource.newBuilder() @@ -325,7 +320,7 @@ public class GrpcBaseTest extends BaseConf { if (telemetryCommandRef.get() == null) { return false; } - if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.APPLY_PASSIVE_SETTINGS_COMMAND) { + if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.SETTINGS) { return false; } return telemetryCommandRef.get() != null; @@ -353,7 +348,7 @@ public class GrpcBaseTest extends BaseConf { assertEndTransactionResponse(endTransactionResponse); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setReportActiveSettingsCommand(buildPushConsumerClientSettings()) + .setSettings(buildPushConsumerClientSettings()) .build()); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { @@ -557,9 +552,8 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); } - public ReportActiveSettingsCommand buildAccessPointClientSettings(int port) { - return ReportActiveSettingsCommand.newBuilder() - .setNonce(UUID.randomUUID().toString()) + public Settings buildAccessPointClientSettings(int port) { + return Settings.newBuilder() .setAccessPoint(Endpoints.newBuilder() .setScheme(AddressScheme.IPv4) .addAddresses(Address.newBuilder() @@ -570,27 +564,29 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public ReportActiveSettingsCommand buildPushConsumerClientSettings() { + public Settings buildPushConsumerClientSettings() { return buildPushConsumerClientSettings(2, false); } - public ReportActiveSettingsCommand buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { - return ReportActiveSettingsCommand.newBuilder() - .setNonce(UUID.randomUUID().toString()) + public Settings buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + return Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) - .setActiveSubscriptionSettings(ActiveSubscriptionSettings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) + .setFifo(fifo) .build()) .build(); } - public ReportActiveSettingsCommand buildProducerClientSettings(String... topics) { + public Settings buildProducerClientSettings(String... topics) { List topicResources = Arrays.stream(topics).map(topic -> Resource.newBuilder().setName(topic).build()) .collect(Collectors.toList()); - return ReportActiveSettingsCommand.newBuilder() - .setNonce(UUID.randomUUID().toString()) + return Settings.newBuilder() .setClientType(ClientType.PRODUCER) - .setActivePublishingSettings(ActivePublishingSettings.newBuilder() - .addAllPublishingTopics(topicResources) + .setPublishing(Publishing.newBuilder() + .addAllTopics(topicResources) .build()) .build(); } From 69e5ef2451af486e6b0a732787513dbc7fa9d665 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 11:31:50 +0800 Subject: [PATCH 112/338] [ISSUE #3949] v2 support --- .../apache/rocketmq/common/constant/LoggerName.java | 1 - .../java/org/apache/rocketmq/proxy/ProxyStartup.java | 6 ++++-- .../rocketmq/proxy/channel/ChannelManager.java | 6 +++--- .../apache/rocketmq/proxy/channel/SimpleChannel.java | 6 +++--- .../apache/rocketmq/proxy/config/Configuration.java | 3 ++- .../proxy/connector/client/MQClientAPIExt.java | 9 +++++---- .../connector/factory/AbstractClientManager.java | 7 ++++--- .../proxy/connector/route/TopicRouteCache.java | 7 ++++--- .../TransactionHeartbeatRegisterService.java | 7 ++++--- .../proxy/connector/transaction/TransactionId.java | 7 ++++--- .../org/apache/rocketmq/proxy/grpc/GrpcServer.java | 6 +++--- .../proxy/grpc/v1/GrpcMessagingProcessor.java | 8 ++++---- .../proxy/grpc/v1/adapter/GrpcConverter.java | 6 +++--- .../proxy/grpc/v1/service/ClusterGrpcService.java | 6 +++--- .../proxy/grpc/v2/adapter/GrpcConverter.java | 6 +++--- .../proxy/grpc/v2/adapter/ResponseWriter.java | 6 +++--- .../handler/ReceiveMessageResponseHandler.java | 6 +++--- .../proxy/grpc/v2/service/ClusterGrpcService.java | 6 +++--- .../proxy/grpc/v2/service/LocalGrpcService.java | 6 +++--- .../service/cluster/DefaultWriteQueueSelector.java | 7 ++++--- .../v2/service/cluster/ForwardClientService.java | 7 ++++--- .../grpc/v2/service/cluster/ProducerServiceTest.java | 12 ------------ 22 files changed, 69 insertions(+), 72 deletions(-) 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 3d764b56dd..244c5de772 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 @@ -45,5 +45,4 @@ public class LoggerName { public static final String FAILOVER_LOGGER_NAME = "RocketmqFailover"; public static final String STDOUT_LOGGER_NAME = "STDOUT"; public static final String PROXY_LOGGER_NAME = "RocketmqProxy"; - public static final String GRPC_LOGGER_NAME = "RocketmqGrpc"; } 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 57239a7954..a4b1371de9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -24,7 +24,10 @@ import java.util.Date; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.BrokerStartup; import org.apache.rocketmq.client.log.ClientLogger; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -34,11 +37,10 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ProxyStartup { - private static final Logger log = LoggerFactory.getLogger(ProxyStartup.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private static final ProxyStartAndShutdown PROXY_START_AND_SHUTDOWN = new ProxyStartAndShutdown(); private static class ProxyStartAndShutdown extends AbstractStartAndShutdown { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index aae433f54c..29bb2d671b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -27,14 +27,14 @@ import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ChannelManager { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java index 31b762294d..14fd885529 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java @@ -30,8 +30,8 @@ import io.netty.util.concurrent.GlobalEventExecutor; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.apache.rocketmq.common.constant.LoggerName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; /** * SimpleChannel is used to handle writeAndFlush situation in processor @@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory; * @see io.netty.channel.Channel#writeAndFlush */ public class SimpleChannel extends AbstractChannel { - protected static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final String remoteAddress; protected final String localAddress; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java index 29d14d5aa6..89eed7fa93 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java @@ -21,11 +21,12 @@ import com.alibaba.fastjson.JSON; import java.io.File; import java.nio.file.Files; import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.constant.LoggerName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Configuration { - private final static Logger log = LoggerFactory.getLogger(Configuration.class); + private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final AtomicReference proxyConfigReference = new AtomicReference<>(); public void init() throws Exception { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java index b2d9cf9330..f84fc38973 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java @@ -35,6 +35,7 @@ import org.apache.rocketmq.client.impl.CommunicationMode; import org.apache.rocketmq.client.impl.MQClientAPIImpl; import org.apache.rocketmq.client.impl.consumer.PullResultExt; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; @@ -56,16 +57,16 @@ import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class MQClientAPIExt extends MQClientAPIImpl { - private static final Logger LOGGER = LoggerFactory.getLogger(MQClientAPIExt.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ClientConfig clientConfig; @@ -82,7 +83,7 @@ public class MQClientAPIExt extends MQClientAPIImpl { public boolean updateNameServerAddressList() { if (this.clientConfig.getNamesrvAddr() != null) { this.updateNameServerAddressList(this.clientConfig.getNamesrvAddr()); - LOGGER.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); + log.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr()); return true; } return false; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java index 190afd1f8a..4a6f0591ca 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java @@ -19,13 +19,14 @@ package org.apache.rocketmq.proxy.connector.factory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.netty.NettyClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public abstract class AbstractClientManager { - private static final Logger log = LoggerFactory.getLogger(AbstractClientManager.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final ScheduledExecutorService scheduledExecutorService; protected Map cacheTable = new ConcurrentHashMap<>(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java index ad4ed98106..ff6a653160 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java @@ -24,19 +24,20 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractCacheLoader; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class TopicRouteCache { - private static final Logger log = LoggerFactory.getLogger(TopicRouteCache.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final LoadingCache topicCache; private final ThreadPoolExecutor cacheRefreshExecutor; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java index d754910f5d..830bd29b69 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -28,21 +28,22 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class TransactionHeartbeatRegisterService implements StartAndShutdown { - private static final Logger log = LoggerFactory.getLogger(TransactionHeartbeatRegisterService.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private static final String TRANS_HEARTBEAT_CLIENT_ID = "rmq-proxy-producer-client"; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java index e0d5a4ee20..e0614c2636 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java @@ -26,15 +26,16 @@ import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.UtilAll; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageId; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class TransactionId { - private static final Logger log = LoggerFactory.getLogger(TransactionId.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private SocketAddress brokerAddr; private String brokerTransactionId; 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 2167ac08cd..484e926de6 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 @@ -36,6 +36,8 @@ import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.common.utils.ServiceProvider; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; @@ -43,11 +45,9 @@ import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class GrpcServer implements StartAndShutdown { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final io.grpc.Server server; private final ThreadPoolExecutor executor; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java index bfafbdb777..761b247e62 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java @@ -59,15 +59,15 @@ import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.grpc.v1.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final GrpcForwardService grpcForwardService; public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java index 7be0496eef..cf832205e8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java @@ -89,15 +89,15 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class GrpcConverter { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); public static String wrapResourceWithNamespace(Resource resource) { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java index f39857ba84..a0746f8a79 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java @@ -55,14 +55,14 @@ import com.google.rpc.Code; import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v1.adapter.V2Converter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService clusterGrpcService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 6da864d1b6..d0c8fb9a71 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -85,15 +85,15 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class GrpcConverter { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); public static String wrapResourceWithNamespace(Resource resource) { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 653d9d7e10..11f4416633 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -20,11 +20,11 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import org.apache.rocketmq.common.constant.LoggerName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); public static void write(StreamObserver observer, final T response) { if (observer instanceof ServerCallStreamObserver) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 8b54b8b80f..645e4bed75 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -36,16 +36,16 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.InvocationContext; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ReceiveMessageResponseHandler implements ResponseHandler { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final String brokerName; private final boolean fifo; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 100792bf6f..6cd445ed60 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -47,6 +47,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -60,11 +62,9 @@ import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 901e6d4989..b79bbd5f9f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -78,6 +78,8 @@ import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.InvocationContext; import org.apache.rocketmq.proxy.channel.SimpleChannel; @@ -102,11 +104,9 @@ import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final BrokerController brokerController; private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java index f5630848f7..f11dc142c0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java @@ -20,16 +20,17 @@ import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class DefaultWriteQueueSelector implements WriteQueueSelector { - private static final Logger log = LoggerFactory.getLogger(DefaultWriteQueueSelector.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final TopicRouteCache topicRouteCache; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 1124685d32..e62b18a113 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -38,8 +38,11 @@ import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.broker.client.ProducerGroupEvent; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -51,11 +54,9 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; import org.apache.rocketmq.remoting.protocol.LanguageCode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ForwardClientService extends BaseService { - private static final Logger log = LoggerFactory.getLogger(ForwardClientService.class); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ChannelManager channelManager; private final ConsumerManager consumerManager; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 1b4c15fd52..727150fc67 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -164,16 +164,4 @@ public class ProducerServiceTest extends BaseServiceTest { assertSame(ex, e.getCause()); } } - -// @Test -// public void testForwardMessageToDeadLetterQueue() throws Exception { -// ProducerService producerService = new ProducerService(this.connectorManager); -// -// when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); -// producerService.forwardMessageToDeadLetterQueue(Context.current(), ForwardMessageToDeadLetterQueueRequest.newBuilder() -// .setMessageId("msgId") -// .setReceiptHandle(createReceiptHandle().encode()) -// .set -// .build()); -// } } \ No newline at end of file From 149a4358d7a424bb799da5b0dc2a0b6787279c3b Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 11:34:44 +0800 Subject: [PATCH 113/338] [ISSUE #3949] v2 support --- .../grpc/v2/adapter/handler/SendMessageResponseHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java index fcf63a9cce..0cbcd56a24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java @@ -25,16 +25,16 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.InvocationContext; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class SendMessageResponseHandler implements ResponseHandler { - private static final Logger log = LoggerFactory.getLogger(LoggerName.GRPC_LOGGER_NAME); + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final String messageId; private final int sysFlag; private final String localAddress; From d43f6f4344b2b734f3d390d4abb16032c8a9bae5 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 22 Apr 2022 10:12:40 +0800 Subject: [PATCH 114/338] [ISSUE #3949] Support batch ack --- .../grpc/v2/service/LocalGrpcService.java | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index b79bbd5f9f..63a09cbd1a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -17,8 +17,10 @@ package org.apache.rocketmq.proxy.grpc.v2.service; +import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; @@ -48,6 +50,7 @@ import apache.rocketmq.v2.VerifyMessageResult; import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -92,6 +95,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; @@ -286,21 +290,39 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { Channel channel = channelManager.createChannel(); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, null); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); - command.makeCustomHeaderToNet(); - CompletableFuture future = new CompletableFuture<>(); - try { - RemotingCommand responseCommand = brokerController.getAckMessageProcessor() - .processRequest(channelHandlerContext, command); - AckMessageResponse.Builder builder = AckMessageResponse.newBuilder(); - builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); - AckMessageResponse response = builder.build(); - future.complete(response); - } catch (Exception e) { - log.error("Exception raised when ack message", e); + List ackMessageResultEntryList = new ArrayList<>(); + for (AckMessageEntry entry : request.getEntriesList()) { + ReceiptHandle receiptHandle = ReceiptHandle.decode(entry.getReceiptHandle()); + if (receiptHandle.isExpired()) { + throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); + } + AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, receiptHandle); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); + command.makeCustomHeaderToNet(); + + try { + RemotingCommand responseCommand = brokerController.getAckMessageProcessor() + .processRequest(channelHandlerContext, command); + ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() + .setReceiptHandle(entry.getReceiptHandle()) + .setMessageId(entry.getMessageId()) + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + .build()); + } catch (Exception e) { + log.error("Exception raised when ack message", e); + ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() + .setReceiptHandle(entry.getReceiptHandle()) + .setMessageId(entry.getMessageId()) + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, e.getMessage())) + .build()); + } } + AckMessageResponse response = AckMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, "ok")) + .addAllEntries(ackMessageResultEntryList) + .build(); + future.complete(response); return future; } From 051fcb87da69250ba6b736384a3cd62f2b2b34bd Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 22 Apr 2022 14:00:20 +0800 Subject: [PATCH 115/338] [ISSUE #3949] Support v2 protocol --- .../rocketmq/proxy/channel/SimpleChannel.java | 2 +- .../ReceiveMessageResponseHandler.java | 1 - .../grpc/v2/service/LocalGrpcService.java | 7 +- .../grpc/v2/service/LocalGrpcServiceTest.java | 203 ++++-------------- 4 files changed, 48 insertions(+), 165 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java index 14fd885529..a9869ec1e6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java @@ -39,7 +39,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; * @see io.netty.channel.Channel#writeAndFlush */ public class SimpleChannel extends AbstractChannel { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final String remoteAddress; protected final String localAddress; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 645e4bed75..edfd795c4e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -57,7 +57,6 @@ public class ReceiveMessageResponseHandler implements ResponseHandler context) { - ReceiveMessageRequest request = context.getRequest(); CompletableFuture future = context.getResponse(); long currentTimeInMillis = System.currentTimeMillis(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 63a09cbd1a..faf09fef56 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -91,7 +91,6 @@ import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; @@ -257,15 +256,13 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); // TODO: get fifo config from subscriptionGroupManager boolean fifo = false; PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); - ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), - fifo); + ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -332,7 +329,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); - int maxReconsumeTimes = ConfigurationManager.getProxyConfig().getDefaultMaxDeliveryAttempts(); + int maxReconsumeTimes = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxReconsumeTimes) { ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index c80b97291f..8c93da865d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -17,14 +17,13 @@ package org.apache.rocketmq.proxy.grpc.v2.service; +import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ClientSettings; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.DeadLetterPolicy; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -37,14 +36,10 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.Publishing; -import apache.rocketmq.v2.PullMessageRequest; -import apache.rocketmq.v2.PullMessageResponse; -import apache.rocketmq.v2.QueryOffsetPolicy; -import apache.rocketmq.v2.QueryOffsetRequest; -import apache.rocketmq.v2.QueryOffsetResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Settings; @@ -53,7 +48,6 @@ import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; -import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.Metadata; @@ -66,6 +60,10 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.broker.processor.AckMessageProcessor; import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; import org.apache.rocketmq.broker.processor.ClientManageProcessor; @@ -83,9 +81,8 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader; -import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; @@ -94,7 +91,6 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.apache.rocketmq.store.MessageStore; import org.apache.rocketmq.store.config.MessageStoreConfig; import org.junit.Before; import org.junit.Test; @@ -117,6 +113,10 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { private PullMessageProcessor pullMessageProcessorMock; @Mock private BrokerController brokerControllerMock; + @Mock + private ConsumerManager consumerManagerMock; + @Mock + private ProducerManager producerManagerMock; @Mock private TelemetryCommandManager telemetryCommandManager; @@ -130,9 +130,12 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { super.before(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); - Mockito.when(brokerControllerMock.getPullMessageProcessor()).thenReturn(pullMessageProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); Mockito.when(brokerControllerMock.getMessageStoreConfig()).thenReturn(new MessageStoreConfig()); + Mockito.doNothing().when(consumerManagerMock).appendConsumerIdsChangeListener(Mockito.any(ConsumerIdsChangeListener.class)); + Mockito.doNothing().when(producerManagerMock).appendProducerChangeListener(Mockito.any(ProducerChangeListener.class)); + Mockito.when(brokerControllerMock.getConsumerManager()).thenReturn(consumerManagerMock); + Mockito.when(brokerControllerMock.getProducerManager()).thenReturn(producerManagerMock); localGrpcService = new LocalGrpcService(brokerControllerMock, telemetryCommandManager); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); @@ -151,25 +154,24 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { } }); streamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(ClientSettings.newBuilder().setSettings(Settings.newBuilder() + .setSettings(Settings.newBuilder() .setSubscription(Subscription.newBuilder() - .setDeadLetterPolicy(DeadLetterPolicy.newBuilder() - .setMaxDeliveryAttempts(3).build()).build()).build())) - .build()); + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(3).build()).build()) + .build()).build()); } @Test public void testHeartbeatProducerData() throws Exception { streamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(ClientSettings.newBuilder() - .setSettings(Settings.newBuilder() - .setPublishing(Publishing.newBuilder() - .addTopics(Resource.newBuilder() + .setSettings(Settings.newBuilder() + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder() .setName("topic") - .build()) .build()) .build()) - .setClientType(ClientType.PRODUCER).build()) + .setClientType(ClientType.PRODUCER) + .build()) .build()); RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); @@ -190,7 +192,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Test public void testHeartbeatConsumerData() throws Exception { streamObserver.onNext(TelemetryCommand.newBuilder() - .setClientSettings(ClientSettings.newBuilder() + .setSettings(Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER).build()) .build()); RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); @@ -350,23 +352,22 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(response); - AckMessageRequest request = AckMessageRequest.newBuilder().setReceiptHandle( - ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode() - ).build(); - CompletableFuture grpcFuture = localGrpcService.ackMessage( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + AckMessageRequest request = AckMessageRequest.newBuilder() + .addEntries( + AckMessageEntry.newBuilder() + .setReceiptHandle(ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(System.currentTimeMillis()) + .invisibleTime(1000L) + .reviveQueueId(0) + .topicType("topic") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()) + .build()) + .build(); + CompletableFuture grpcFuture = localGrpcService.ackMessage(Context.current(), request); AckMessageResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @@ -396,10 +397,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .offset(0L) .build().encode() ).build(); - CompletableFuture grpcFuture = localGrpcService.nackMessage( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + CompletableFuture grpcFuture = localGrpcService.nackMessage(Context.current(), request); NackMessageResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @@ -429,9 +427,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build().encode() ).build(); CompletableFuture grpcFuture = localGrpcService.nackMessage( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + Context.current(), request); NackMessageResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @@ -457,9 +453,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build().encode()) .build(); CompletableFuture grpcFuture = localGrpcService.forwardMessageToDeadLetterQueue( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + Context.current(), request); ForwardMessageToDeadLetterQueueResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } @@ -481,77 +475,11 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { ) .build(); CompletableFuture grpcFuture = localGrpcService.endTransaction( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); + Context.current(), request); EndTransactionResponse r = grpcFuture.get(); assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } - @Test - public void testQueryOffset() throws Exception { - String topic = "test-topic"; - int queueId = 1; - - long maxOffset = 10L; - long timeOffset = 5L; - MessageStore messageStore = Mockito.mock(MessageStore.class); - Mockito.when(brokerControllerMock.getMessageStore()).thenReturn(messageStore); - Mockito.when(messageStore.getMaxOffsetInQueue(Mockito.eq(topic), Mockito.eq(queueId))).thenReturn(maxOffset); - Mockito.when(messageStore.getOffsetInQueueByTime(Mockito.eq(topic), Mockito.eq(queueId), Mockito.anyLong())).thenReturn(timeOffset); - - QueryOffsetRequest request = QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setId(queueId) - .build()) - .setPolicy(QueryOffsetPolicy.BEGINNING) - .build(); - CompletableFuture grpcFuture = localGrpcService.queryOffset(Context.current(), request); - QueryOffsetResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(r.getOffset()).isEqualTo(0); - - request = QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setId(queueId) - .build()) - .setPolicy(QueryOffsetPolicy.END) - .build(); - grpcFuture = localGrpcService.queryOffset( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); - r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(r.getOffset()).isEqualTo(maxOffset); - - request = QueryOffsetRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setId(queueId) - .build()) - .setTimePoint(Timestamp.newBuilder() - .setSeconds(1000L) - .build()) - .setPolicy(QueryOffsetPolicy.TIME_POINT) - .build(); - grpcFuture = localGrpcService.queryOffset( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); - r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(r.getOffset()).isEqualTo(timeOffset); - } - @Test public void testReportThreadStackTrace() throws Exception { int opaque = 1; @@ -650,45 +578,4 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { assertThat(handle.getQueueId()).isEqualTo(queueId); assertThat(handle.getOffset()).isEqualTo(offset); } - - @Test - public void testPullMessageSuccess() throws Exception { - String topic = "topic"; - byte[] body = "123".getBytes(StandardCharsets.UTF_8); - MessageExt messageExt = new MessageExt(); - messageExt.setTopic(topic); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody(body); - messageExt.putUserProperty("key", "value"); - - long minOffset = 1L; - long nextOffset = 3L; - long maxOffset = 10L; - PullMessageResponseHeader responseHeader = new PullMessageResponseHeader(); - responseHeader.setMinOffset(minOffset); - responseHeader.setNextBeginOffset(nextOffset); - responseHeader.setMaxOffset(maxOffset); - RemotingCommand remotingCommand = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); - remotingCommand.setBody(MessageDecoder.encode(messageExt, true)); - remotingCommand.makeCustomHeaderToNet(); - Mockito.when(pullMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(remotingCommand); - PullMessageRequest request = PullMessageRequest.newBuilder().getDefaultInstanceForType(); - CompletableFuture grpcFuture = localGrpcService.pullMessage( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach() - .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))), request); - PullMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(r.getMessagesCount()).isEqualTo(1); - assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); - assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); - assertThat(r.getMinOffset()).isEqualTo(minOffset); - assertThat(r.getNextOffset()).isEqualTo(nextOffset); - assertThat(r.getMaxOffset()).isEqualTo(maxOffset); - } } \ No newline at end of file From edab18a32ad64b6bd1fbc75f91a635a65f893367 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 14:05:59 +0800 Subject: [PATCH 116/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/service/cluster/ConsumerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index dfb43d89a8..73a9d0d246 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -132,7 +132,8 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); + // TODO: get fifo config from subscriptionGroupManager + boolean fifo = false; return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } From 3717c163475c80f9f68e96481242bd1bd37054fa Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 16:29:53 +0800 Subject: [PATCH 117/338] [ISSUE #3949] v2 support --- .../proxy/connector/ForwardProducer.java | 17 +++++ .../proxy/grpc/v2/adapter/GrpcConverter.java | 46 +++++------- .../v2/service/cluster/ConsumerService.java | 73 +++++++++++++++++-- .../v2/service/cluster/ProducerService.java | 12 ++- .../v2/service/cluster/BaseServiceTest.java | 1 + .../service/cluster/ConsumerServiceTest.java | 53 +++++++++++++- .../test/grpc/v2/ClusterGrpcTest.java | 5 ++ .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 70 ++++++++++++++++-- 8 files changed, 232 insertions(+), 45 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 442efc9329..355449ba7c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -18,6 +18,8 @@ package org.apache.rocketmq.proxy.connector; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; @@ -106,6 +108,21 @@ public class ForwardProducer extends AbstractForwardClient { }); } + public CompletableFuture sendMessageBackThenAckOrg(String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, + AckMessageRequestHeader ackMessageRequestHeader) { + return sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader,DEFAULT_MQ_CLIENT_TIMEOUT); + } + + public CompletableFuture sendMessageBackThenAckOrg(String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, + AckMessageRequestHeader ackMessageRequestHeader, long timeoutMillis) { + return this.sendMessageBack(brokerAddr, sendMsgBackRequestHeader, timeoutMillis).whenComplete((result, throwable) -> { + if (throwable != null || ResponseCode.SUCCESS != result.getCode()) { + return; + } + this.getClient().ackMessageAsync(brokerAddr, ackMessageRequestHeader, timeoutMillis); + }); + } + public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { return this.sendMessageBack(brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index d0c8fb9a71..7b7269a378 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -235,22 +235,17 @@ public class GrpcConverter { } public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - - AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); - ackMessageRequestHeader.setConsumerGroup(groupName); - ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - ackMessageRequestHeader.setQueueId(handle.getQueueId()); - ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); - ackMessageRequestHeader.setOffset(handle.getOffset()); - return ackMessageRequestHeader; + return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); } public static AckMessageRequestHeader buildAckMessageRequestHeader(NackMessageRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); + } + + public static AckMessageRequestHeader buildAckMessageRequestHeader(Resource topic, Resource group, ReceiptHandle handle) { + String groupName = GrpcConverter.wrapResourceWithNamespace(group); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); ackMessageRequestHeader.setConsumerGroup(groupName); @@ -295,33 +290,30 @@ public class GrpcConverter { public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( NackMessageRequest request, int maxReconsumeTimes) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); - consumerSendMsgBackRequestHeader.setGroup(groupName); - consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); - consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); - return consumerSendMsgBackRequestHeader; + return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, + request.getMessageId(), maxReconsumeTimes); } public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( ForwardMessageToDeadLetterQueueRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); + return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, + request.getMessageId(), request.getMaxDeliveryAttempts()); + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Resource topic, Resource group, ReceiptHandle handle, + String messageId, int maxReconsumeTimes) { + String groupName = GrpcConverter.wrapResourceWithNamespace(group); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); consumerSendMsgBackRequestHeader.setGroup(groupName); consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); + consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); return consumerSendMsgBackRequestHeader; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 73a9d0d246..1c8cea0125 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -22,15 +22,18 @@ import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; @@ -72,6 +75,7 @@ public class ConsumerService extends BaseService { private volatile ReadQueueSelector readQueueSelector; private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackNoMatchedMessageHook; + private volatile ResponseHook forwardToDLQInRecvMessageHook; private volatile ResponseHook ackMessageHook; private volatile ResponseHook nackMessageHook; private volatile ResponseHook changeInvisibleDurationHook; @@ -141,9 +145,10 @@ public class ConsumerService extends BaseService { PopStatus status = result.getPopStatus(); switch (status) { case FOUND: + List messageList = filterMessage(ctx, request, result.getMsgFoundList()); return ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllMessages(checkAndGetMessagesFromPopResult(ctx, request, result)) + .addAllMessages(messageList) .build(); case POLLING_FULL: return ReceiveMessageResponse.newBuilder() @@ -158,20 +163,65 @@ public class ConsumerService extends BaseService { } } - protected List checkAndGetMessagesFromPopResult(Context ctx, ReceiveMessageRequest request, PopResult result) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + protected List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { + if (messageExtList == null || messageExtList.isEmpty()) { + return Collections.emptyList(); + } + Settings settings = grpcClientManager.getClientSettings(ctx); + ClientType clientType = settings.getClientType(); + int maxAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); + Resource topic = request.getMessageQueue().getTopic(); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); - List messages = new ArrayList<>(); - for (MessageExt messageExt : result.getMsgFoundList()) { + List resMessageList = new ArrayList<>(); + for (MessageExt messageExt : messageExtList) { + if (ClientType.SIMPLE_CONSUMER.equals(clientType) && messageExt.getReconsumeTimes() >= maxAttempts) { + forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); + continue; + } if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { this.ackNoMatchedMessage(ctx, request, messageExt); continue; } - messages.add(GrpcConverter.buildMessage(messageExt)); + resMessageList.add(GrpcConverter.buildMessage(messageExt)); + } + return resMessageList; + } + + protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxReconsumeTimes) { + CompletableFuture future = new CompletableFuture<>(); + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); + Resource topic = request.getMessageQueue().getTopic(); + Resource group = request.getGroup(); + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( + topic, + group, + handle, + messageExt.getMsgId(), + maxReconsumeTimes); + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( + topic, + group, + handle); + + future = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); + } catch (Throwable t) { + future.completeExceptionally(t); } - return messages; + future.whenComplete((result, throwable) -> { + if (forwardToDLQInRecvMessageHook != null) { + forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); + } + }); } protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { @@ -444,6 +494,15 @@ public class ConsumerService extends BaseService { this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; } + public ResponseHook getForwardToDLQInRecvMessageHook() { + return forwardToDLQInRecvMessageHook; + } + + public void setForwardToDLQInRecvMessageHook( + ResponseHook forwardToDLQInRecvMessageHook) { + this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; + } + public ResponseHook getAckMessageHook() { return ackMessageHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 1c16dea04f..d40691b3f6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -31,6 +31,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -49,7 +50,6 @@ public class ProducerService extends BaseService { private volatile ResponseHook sendMessageHook; private volatile ResponseHook forwardMessageToDLQHook; - public ProducerService(ConnectorManager connectorManager) { super(connectorManager); this.producer = connectorManager.getForwardProducer(); @@ -123,7 +123,8 @@ public class ProducerService extends BaseService { return Pair.of(requestHeader, message); } - protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, SendResult result) { + protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, + SendResult result) { if (result.getSendStatus() != SendStatus.SEND_OK) { return SendMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) @@ -153,8 +154,11 @@ public class ProducerService extends BaseService { try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - ConsumerSendMsgBackRequestHeader requestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); - CompletableFuture resultFuture = this.producer.sendMessageBack(brokerAddr, requestHeader); + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( + request.getTopic(), request.getGroup(), receiptHandle); + + CompletableFuture resultFuture = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); resultFuture .thenAccept(result -> future.complete( diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java index 347a340ae0..1a05c8675e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java @@ -35,6 +35,7 @@ import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.junit.Before; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index a866e11aaa..12e7fb838f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -3,6 +3,7 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; @@ -15,6 +16,7 @@ import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; import io.grpc.Context; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -30,7 +32,6 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; @@ -105,6 +106,56 @@ public class ConsumerServiceTest extends BaseServiceTest { assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); } + @Test + public void testToDLQInReceiveMessage() throws Exception { + SelectableMessageQueue selectableMessageQueue = new SelectableMessageQueue( + new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); + when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); + + Settings clientSettings = Settings.newBuilder() + .setClientType(ClientType.SIMPLE_CONSUMER) + .setSubscription(Subscription.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(0).build()) + .setFifo(false) + .build()) + .build(); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + + List messageExtList = Lists.newArrayList( + createMessageExt("msg1", "msg1"), + createMessageExt("msg2", "msg2") + ); + PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); + when(readConsumerClient.popMessage(anyString(), anyString(), any(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(popResult)); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + List toDLQMsgId = new ArrayList<>(); + doAnswer(mock -> { + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = mock.getArgument(1); + toDLQMsgId.add(sendMsgBackRequestHeader.getOriginMsgId()); + return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); + }).when(producerClient).sendMessageBackThenAckOrg(anyString(), any(), any()); + + Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); + ReceiveMessageResponse response = consumerService.receiveMessage(ctx, + ReceiveMessageRequest.newBuilder() + .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() + .setTopic(Resource.newBuilder() + .setResourceNamespace("namespace") + .setName("topic") + .build()) + .build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.TAG) + .setExpression("msg1") + .build()) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(2, toDLQMsgId.size()); + } + @Test public void testAckMessage() throws Exception { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index cab6068a61..7258c0d7dd 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -91,4 +91,9 @@ public class ClusterGrpcTest extends GrpcBaseTest { public void testSendReceiveMessageThenToDLQ() throws Exception { super.testSendReceiveMessageThenToDLQ(); } + + @Test + public void testSimpleConsumer() throws Exception { + super.testSimpleConsumer(); + } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 783ecbed4e..8c484df002 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -80,6 +80,7 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import javax.net.ssl.SSLException; @@ -96,7 +97,6 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.junit.Rule; -import org.junit.Test; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; @@ -202,12 +202,12 @@ public class GrpcBaseTest extends BaseConf { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; - this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); - // init consumer offset + this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); receiveMessage(blockingStub, topic, group); String messageId = createUniqID(); + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); @@ -222,13 +222,13 @@ public class GrpcBaseTest extends BaseConf { public void testSendReceiveMessageThenToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); - String group = "group"; // init consumer offset + this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); receiveMessage(blockingStub, topic, group); + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); String messageId = createUniqID(); SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); @@ -278,7 +278,6 @@ public class GrpcBaseTest extends BaseConf { }); } - @Test public void testTransactionCheckThenCommit() { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = "group"; @@ -364,6 +363,53 @@ public class GrpcBaseTest extends BaseConf { } } + public void testSimpleConsumer() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = "group"; + int maxDeliveryAttempts = 2; + boolean fifo = false; + + // init consumer offset + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + receiveMessage(blockingStub, topic, group); + + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + + AtomicInteger receiveMessageCount = new AtomicInteger(0); + + ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); + assertReceiveMessage(receiveResponse, messageId); + receiveMessageCount.incrementAndGet(); + + DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); + defaultMQPullConsumer.start(); + org.apache.rocketmq.common.message.MessageQueue dlqMQ = new org.apache.rocketmq.common.message.MessageQueue(MixAll.getDLQTopic(group), broker1Name, 0); + await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { + try { + ReceiveMessageResponse retryReceiveResponse = receiveMessage(blockingStub, topic, group, 1).get(0); + if (retryReceiveResponse.getMessagesCount() > 0) { + receiveMessageCount.addAndGet(retryReceiveResponse.getMessagesCount()); + } + + PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); + if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { + return false; + } + MessageExt messageExt = pullResult.getMsgFoundList().get(0); + return messageId.equals(messageExt.getMsgId()); + } catch (Throwable ignore) { + return false; + } + }); + + assertThat(receiveMessageCount.get()).isEqualTo(maxDeliveryAttempts); + } + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { List responseList = new ArrayList<>(); Iterator responseIterator = stub.withDeadlineAfter(15, TimeUnit.SECONDS) @@ -564,6 +610,18 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public Settings buildSimpleConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + return Settings.newBuilder() + .setClientType(ClientType.SIMPLE_CONSUMER) + .setSubscription(Subscription.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) + .setFifo(fifo) + .build()) + .build(); + } + public Settings buildPushConsumerClientSettings() { return buildPushConsumerClientSettings(2, false); } From f36fc44a3f2631525d7978ac3baf85a32660e3e7 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 16:35:30 +0800 Subject: [PATCH 118/338] [ISSUE #3949] v2 test cases --- .../apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java | 4 ++-- .../apache/rocketmq/test/grpc/v2/GrpcBaseTest.java | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 7258c0d7dd..3a7ff341d0 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -93,7 +93,7 @@ public class ClusterGrpcTest extends GrpcBaseTest { } @Test - public void testSimpleConsumer() throws Exception { - super.testSimpleConsumer(); + public void testSimpleConsumerToDLQ() throws Exception { + super.testSimpleConsumerToDLQ(); } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 8c484df002..75c881039b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -96,6 +96,7 @@ import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; +import org.apache.rocketmq.test.util.MQRandomUtils; import org.junit.Rule; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; @@ -200,7 +201,7 @@ public class GrpcBaseTest extends BaseConf { public void testSendReceiveMessage() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = "group"; + String group = MQRandomUtils.getRandomConsumerGroup(); // init consumer offset this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); @@ -222,7 +223,7 @@ public class GrpcBaseTest extends BaseConf { public void testSendReceiveMessageThenToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = "group"; + String group = MQRandomUtils.getRandomConsumerGroup(); // init consumer offset this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); @@ -280,7 +281,7 @@ public class GrpcBaseTest extends BaseConf { public void testTransactionCheckThenCommit() { String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = "group"; + String group = MQRandomUtils.getRandomConsumerGroup(); AtomicReference telemetryCommandRef = new AtomicReference<>(null); StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { @@ -363,9 +364,9 @@ public class GrpcBaseTest extends BaseConf { } } - public void testSimpleConsumer() throws Exception { + public void testSimpleConsumerToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = "group"; + String group = MQRandomUtils.getRandomConsumerGroup(); int maxDeliveryAttempts = 2; boolean fifo = false; From 6b877b5bddfc96c27406dece12f0b672da3aa5c5 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 22 Apr 2022 18:00:01 +0800 Subject: [PATCH 119/338] [ISSUE #3949] v2 test cases --- .../TransactionalMessageCheckService.java | 2 +- .../grpc/v2/adapter/ResponseBuilder.java | 2 +- .../v2/service/cluster/ConsumerService.java | 135 +++++++---------- .../v2/service/cluster/ProducerService.java | 60 +++----- .../test/grpc/v2/ClusterGrpcTest.java | 6 + .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 136 +++++++++++++++--- .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 10 ++ 7 files changed, 206 insertions(+), 145 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java index 143889a19c..6a3c2d2b29 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionalMessageCheckService.java @@ -42,8 +42,8 @@ public class TransactionalMessageCheckService extends ServiceThread { @Override public void run() { log.info("Start transaction check service thread!"); - long checkInterval = brokerController.getBrokerConfig().getTransactionCheckInterval(); while (!this.isStopped()) { + long checkInterval = brokerController.getBrokerConfig().getTransactionCheckInterval(); this.waitForRunning(checkInterval); } log.info("End transaction check service thread!"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index 27be2f4333..5ae5abde19 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -29,7 +29,7 @@ public class ResponseBuilder { t = t.getCause(); } if (t instanceof ProxyException) { - ProxyException proxyException = (ProxyException) t.getCause(); + ProxyException proxyException = (ProxyException) t; return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); } return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 1c8cea0125..819349ede5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -96,12 +96,6 @@ public class ConsumerService extends BaseService { public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); - // register hook. - future.whenComplete((response, throwable) -> { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); try { PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); @@ -111,26 +105,20 @@ public class ConsumerService extends BaseService { throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); } - CompletableFuture popResultFuture = this.readConsumer.popMessage( + future = this.readConsumer.popMessage( messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), requestHeader, - requestHeader.getPollTime()); - popResultFuture - .thenAccept(result -> { - try { - future.complete(convertToReceiveMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + requestHeader.getPollTime()) + .thenApply(result -> convertToReceiveMessageResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); } + future.whenComplete((response, throwable) -> { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(ctx, request, response, throwable); + } + }); return future; } @@ -141,7 +129,8 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } - protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { + protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, + PopResult result) { PopStatus status = result.getPopStatus(); switch (status) { case FOUND: @@ -189,7 +178,8 @@ public class ConsumerService extends BaseService { return resMessageList; } - protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxReconsumeTimes) { + protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, + int maxReconsumeTimes) { CompletableFuture future = new CompletableFuture<>(); ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); @@ -286,7 +276,8 @@ public class ConsumerService extends BaseService { return future; } - protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, AckMessageEntry ackMessageEntry) { + protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, + AckMessageEntry ackMessageEntry) { CompletableFuture future = new CompletableFuture<>(); AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) @@ -311,11 +302,13 @@ public class ConsumerService extends BaseService { return future; } - protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, ReceiptHandle handle) { + protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, + ReceiptHandle handle) { return GrpcConverter.buildAckMessageRequestHeader(request, handle); } - protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, AckResult ackResult) { + protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, + AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return AckMessageResultEntry.newBuilder() .setMessageId(ackMessageEntry.getMessageId()) @@ -332,11 +325,6 @@ public class ConsumerService extends BaseService { public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (nackMessageHook != null) { - nackMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); @@ -344,51 +332,35 @@ public class ConsumerService extends BaseService { Settings settings = grpcClientManager.getClientSettings(ctx); int maxDeliveryAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { - CompletableFuture resultFuture = this.producer.sendMessageBack( + future = this.producer.sendMessageBack( brokerAddr, this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts) - ); - - resultFuture - .thenAccept(result -> { - try { - future.complete(convertToNackMessageResponse(ctx, request, result)); - if (result.getCode() == ResponseCode.SUCCESS) { - writeConsumer.ackMessage( - brokerAddr, - this.buildAckMessageRequestHeader(ctx, request)); - } - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + ).thenApply(result -> { + if (result.getCode() == ResponseCode.SUCCESS) { + writeConsumer.ackMessage( + brokerAddr, + this.buildAckMessageRequestHeader(ctx, request)); + } + return convertToNackMessageResponse(ctx, request, result); + }); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); - CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); - resultFuture - .thenAccept(result -> { - try { - future.complete(convertToNackMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + future = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader) + .thenApply(result -> convertToNackMessageResponse(ctx, request, result)); } } catch (Throwable t) { future.completeExceptionally(t); } + future.whenComplete((response, throwable) -> { + if (nackMessageHook != null) { + nackMessageHook.beforeResponse(ctx, request, response, throwable); + } + }); return future; } - protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { + protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, + NackMessageRequest request) { return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); } @@ -396,12 +368,14 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildAckMessageRequestHeader(request); } - protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, NackMessageRequest request, + protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, + NackMessageRequest request, int maxReconsumeTimes) { return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); } - protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, AckResult ackResult) { + protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, + AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return NackMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) @@ -412,7 +386,8 @@ public class ConsumerService extends BaseService { .build(); } - protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, RemotingCommand sendMsgBackToDLQResult) { + protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, + RemotingCommand sendMsgBackToDLQResult) { return NackMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) .build(); @@ -421,32 +396,22 @@ public class ConsumerService extends BaseService { public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (changeInvisibleDurationHook != null) { - changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); - } - }); + try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); - CompletableFuture resultFuture = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader); - resultFuture - .thenAccept(result -> { - try { - future.complete(convertToChangeInvisibleDurationResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + future = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader) + .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); } + future.whenComplete((response, throwable) -> { + if (changeInvisibleDurationHook != null) { + changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); + } + }); return future; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index d40691b3f6..55d6fe5bf7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -71,11 +71,6 @@ public class ProducerService extends BaseService { public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (sendMessageHook != null) { - sendMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); try { Pair> requestPair = this.buildSendMessageRequest(ctx, request); @@ -89,28 +84,21 @@ public class ProducerService extends BaseService { } // send message to broker. - CompletableFuture sendResultCompletableFuture = this.producer.sendMessage( + future = this.producer.sendMessage( selectableMessageQueue.getBrokerAddr(), selectableMessageQueue.getBrokerName(), message, requestHeader - ); - - sendResultCompletableFuture - .thenAccept(result -> { - try { - future.complete(convertToSendMessageResponse(ctx, request, result)); - } catch (Throwable throwable) { - future.completeExceptionally(throwable); - } - }) - .exceptionally(e -> { - future.completeExceptionally(e); - return null; - }); + ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); } + + future.whenComplete((response, throwable) -> { + if (sendMessageHook != null) { + sendMessageHook.beforeResponse(ctx, request, response, throwable); + } + }); return future; } @@ -145,11 +133,6 @@ public class ProducerService extends BaseService { public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (forwardMessageToDLQHook != null) { - forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); - } - }); try { ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); @@ -158,22 +141,16 @@ public class ProducerService extends BaseService { AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( request.getTopic(), request.getGroup(), receiptHandle); - CompletableFuture resultFuture = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); - resultFuture - .thenAccept(result -> - future.complete( - ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) - .build() - ) - ) - .exceptionally(throwable -> { - future.completeExceptionally(throwable); - return null; - }); + future = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) + .thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); } catch (Throwable t) { future.completeExceptionally(t); } + future.whenComplete((response, throwable) -> { + if (forwardMessageToDLQHook != null) { + forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); + } + }); return future; } @@ -181,4 +158,11 @@ public class ProducerService extends BaseService { ForwardMessageToDeadLetterQueueRequest request) { return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); } + + protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, + RemotingCommand result) { + return ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) + .build(); + } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 3a7ff341d0..84fa336a3e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -40,6 +40,7 @@ public class ClusterGrpcTest extends GrpcBaseTest { @Before public void setUp() throws Exception { super.setUp(); + ConfigurationManager.getProxyConfig().setTransactionHeartbeatPeriodSecond(3); grpcForwardService = new ClusterGrpcService(); grpcForwardService.start(); GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); @@ -92,6 +93,11 @@ public class ClusterGrpcTest extends GrpcBaseTest { super.testSendReceiveMessageThenToDLQ(); } + @Test + public void testSimpleConsumerSendAndRecv() throws Exception { + super.testSimpleConsumerSendAndRecv(); + } + @Test public void testSimpleConsumerToDLQ() throws Exception { super.testSimpleConsumerToDLQ(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 75c881039b..97e714f49e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -20,8 +20,11 @@ package org.apache.rocketmq.test.grpc.v2; import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.Address; import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; @@ -54,6 +57,7 @@ import apache.rocketmq.v2.TransactionResolution; import apache.rocketmq.v2.TransactionSource; import com.google.protobuf.ByteString; import com.google.protobuf.Duration; +import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; import io.grpc.Channel; import io.grpc.Metadata; @@ -77,6 +81,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -120,6 +125,10 @@ public class GrpcBaseTest extends BaseConf { protected static final int defaultQueueNums = 8; public void setUp() throws Exception { + brokerController1.getBrokerConfig().setTransactionCheckInterval(3 * 1000); + brokerController2.getBrokerConfig().setTransactionCheckInterval(3 * 1000); + brokerController3.getBrokerConfig().setTransactionCheckInterval(3 * 1000); + header.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); header.put(InterceptorConstants.LANGUAGE, "JAVA"); @@ -148,7 +157,8 @@ public class GrpcBaseTest extends BaseConf { return MetadataUtils.attachHeaders(stub, header); } - protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, Settings clientSettings) { + protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, + Settings clientSettings) { CompletableFuture future = new CompletableFuture<>(); StreamObserver requestStreamObserver = stub.telemetry(new DefaultTelemetryCommandStreamObserver() { @Override @@ -217,8 +227,8 @@ public class GrpcBaseTest extends BaseConf { ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(response, messageId); String receiptHandle = response.getMessages(0).getSystemProperties().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, topic, messageId, receiptHandle)); - assertAck(ackMessageResponse); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, messageId, receiptHandle)); + assertAllAckOk(ackMessageResponse); } public void testSendReceiveMessageThenToDLQ() throws Exception { @@ -241,7 +251,7 @@ public class GrpcBaseTest extends BaseConf { Message message = receiveResponse.getMessages(0); NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 1 + topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 1 )); assertNackMessageResponse(nackMessageResponse); @@ -258,7 +268,7 @@ public class GrpcBaseTest extends BaseConf { message = receiveRetryResponseRef.get().getMessages(0); nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - group, topic, messageId, message.getSystemProperties().getReceiptHandle(), 2 + topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 2 )); assertNackMessageResponse(nackMessageResponse); @@ -331,7 +341,7 @@ public class GrpcBaseTest extends BaseConf { SendMessageResponse sendResponse = blockingStub.sendMessage(buildTransactionSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); - await().atMost(java.time.Duration.ofSeconds(60)).until(() -> { + await().atMost(java.time.Duration.ofSeconds(90)).until(() -> { if (telemetryCommandRef.get() == null) { return false; } @@ -364,6 +374,64 @@ public class GrpcBaseTest extends BaseConf { } } + public void testSimpleConsumerSendAndRecv() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = MQRandomUtils.getRandomConsumerGroup(); + int maxDeliveryAttempts = 16; + boolean fifo = false; + + // init consumer offset + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + receiveMessage(blockingStub, topic, group); + + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + + ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); + assertReceiveMessage(receiveResponse, messageId); + + String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); + ChangeInvisibleDurationResponse changeResponse = blockingStub.changeInvisibleDuration(buildChangeInvisibleDurationRequest(topic, group, receiptHandle, 5)); + assertChangeInvisibleDurationResponse(changeResponse, receiptHandle); + + List ackHandles = new ArrayList<>(); + ackHandles.add(changeResponse.getReceiptHandle()); + + await().atMost(java.time.Duration.ofSeconds(20)).until(() -> { + ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); + if (receiveRetryResponse.getMessagesCount() <= 0) { + return false; + } + if (receiveRetryResponse.getMessages(0).getSystemProperties() + .getMessageId().equals(messageId)) { + ackHandles.add(receiveRetryResponse.getMessages(0).getSystemProperties().getReceiptHandle()); + return true; + } + return false; + }); + + assertThat(ackHandles.size()).isEqualTo(2); + AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, + AckMessageEntry.newBuilder().setMessageId(messageId).setReceiptHandle(ackHandles.get(0)).build(), + AckMessageEntry.newBuilder().setMessageId(messageId).setReceiptHandle(ackHandles.get(1)).build())); + assertThat(ackMessageResponse.getStatus().getCode()).isEqualTo(Code.OK); + int okNum = 0; + int expireNum = 0; + for (AckMessageResultEntry entry : ackMessageResponse.getEntriesList()) { + if (entry.getStatus().getCode().equals(Code.OK)) { + okNum++; + } else if (entry.getStatus().getCode().equals(Code.RECEIPT_HANDLE_EXPIRED)) { + expireNum++; + } + } + assertThat(okNum).isEqualTo(1); + assertThat(expireNum).isEqualTo(1); + } + public void testSimpleConsumerToDLQ() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); @@ -411,20 +479,22 @@ public class GrpcBaseTest extends BaseConf { assertThat(receiveMessageCount.get()).isEqualTo(maxDeliveryAttempts); } - public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, + String topic, String group) { List responseList = new ArrayList<>(); Iterator responseIterator = stub.withDeadlineAfter(15, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); + .receiveMessage(buildReceiveMessageRequest(topic, group)); while (responseIterator.hasNext()) { responseList.add(responseIterator.next()); } return responseList; } - public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group, int timeSeconds) { + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, + String topic, String group, int timeSeconds) { List responseList = new ArrayList<>(); - Iterator responseIterator = stub.withDeadlineAfter(timeSeconds, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, topic)); + Iterator responseIterator = stub.withDeadlineAfter(timeSeconds, TimeUnit.SECONDS) + .receiveMessage(buildReceiveMessageRequest(topic, group)); while (responseIterator.hasNext()) { responseList.add(responseIterator.next()); } @@ -493,7 +563,7 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public ReceiveMessageRequest buildReceiveMessageRequest(String group, String topic) { + public ReceiveMessageRequest buildReceiveMessageRequest(String topic, String group) { return ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder() .setName(group) @@ -511,7 +581,15 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public AckMessageRequest buildAckMessageRequest(String group, String topic, String messageId, String receiptHandle) { + public AckMessageRequest buildAckMessageRequest(String topic, String group, String messageId, + String receiptHandle) { + return buildAckMessageRequest(topic, group, AckMessageEntry.newBuilder() + .setMessageId(messageId) + .setReceiptHandle(receiptHandle) + .build()); + } + + public AckMessageRequest buildAckMessageRequest(String topic, String group, AckMessageEntry... entry) { return AckMessageRequest.newBuilder() .setGroup(Resource.newBuilder() .setName(group) @@ -519,14 +597,12 @@ public class GrpcBaseTest extends BaseConf { .setTopic(Resource.newBuilder() .setName(topic) .build()) - .addEntries(AckMessageEntry.newBuilder() - .setMessageId(messageId) - .setReceiptHandle(receiptHandle) - .build()) + .addAllEntries(Arrays.stream(entry).collect(Collectors.toList())) .build(); } - public NackMessageRequest buildNackMessageRequest(String group, String topic, String messageId, String receiptHandle, + public NackMessageRequest buildNackMessageRequest(String topic, String group, String messageId, + String receiptHandle, int deliveryAttempt) { return NackMessageRequest.newBuilder() .setDeliveryAttempt(deliveryAttempt) @@ -541,7 +617,8 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public EndTransactionRequest buildEndTransactionRequest(String topic, String messageId, String transactionId, TransactionResolution resolution) { + public EndTransactionRequest buildEndTransactionRequest(String topic, String messageId, String transactionId, + TransactionResolution resolution) { return EndTransactionRequest.newBuilder() .setMessageId(messageId) .setTopic(Resource.newBuilder() @@ -553,6 +630,16 @@ public class GrpcBaseTest extends BaseConf { .build(); } + public ChangeInvisibleDurationRequest buildChangeInvisibleDurationRequest(String topic, String group, + String receiptHandle, int second) { + return ChangeInvisibleDurationRequest.newBuilder() + .setTopic(Resource.newBuilder().setName(topic).build()) + .setGroup(Resource.newBuilder().setName(group).build()) + .setInvisibleDuration(Durations.fromSeconds(second)) + .setReceiptHandle(receiptHandle) + .build(); + } + public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); @@ -580,9 +667,13 @@ public class GrpcBaseTest extends BaseConf { .getMessageId()).isEqualTo(messageId); } - public void assertAck(AckMessageResponse response) { + public void assertAllAckOk(AckMessageResponse response) { assertThat(response.getStatus() .getCode()).isEqualTo(Code.OK); + for (AckMessageResultEntry entry : response.getEntriesList()) { + assertThat(entry.getStatus() + .getCode()).isEqualTo(Code.OK); + } } public void assertNackMessageResponse(NackMessageResponse response) { @@ -599,6 +690,11 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); } + public void assertChangeInvisibleDurationResponse(ChangeInvisibleDurationResponse response, String prevHandle) { + assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getReceiptHandle()).isNotEqualTo(prevHandle); + } + public Settings buildAccessPointClientSettings(int port) { return Settings.newBuilder() .setAccessPoint(Endpoints.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index 282fff469b..6ddefba797 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -66,4 +66,14 @@ public class LocalGrpcTest extends GrpcBaseTest { public void testSendReceiveMessageThenToDLQ() throws Exception { super.testSendReceiveMessageThenToDLQ(); } + + @Test + public void testSimpleConsumerSendAndRecv() throws Exception { + super.testSimpleConsumerSendAndRecv(); + } + + @Test + public void testSimpleConsumerToDLQ() throws Exception { + super.testSimpleConsumerToDLQ(); + } } From 9baa0070732c29f7023ad5e22309e807eadc838b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 22 Apr 2022 19:42:41 +0800 Subject: [PATCH 120/338] [ISSUE #3949] Fix request mapping --- .../apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index 304d23e9ec..d659c58598 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -44,7 +44,7 @@ public class RequestMapping { put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); @@ -58,7 +58,7 @@ public class RequestMapping { put(apache.rocketmq.v1.AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); put(apache.rocketmq.v1.NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); put(apache.rocketmq.v1.QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); put(apache.rocketmq.v1.PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); put(apache.rocketmq.v1.NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); From a081ef4b296188e1c1f5cf17862b305c841e8095 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sun, 24 Apr 2022 10:28:30 +0800 Subject: [PATCH 121/338] [ISSUE #3949] v2 support --- .../grpc/v2/service/GrpcClientManager.java | 37 ++++++++++++++++++- .../v2/service/cluster/ConsumerService.java | 3 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index 2a93676e7b..f784c7fe29 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -17,14 +17,44 @@ package org.apache.rocketmq.proxy.grpc.v2.service; +import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import com.google.protobuf.util.Durations; import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { - + + private static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() + .setPublishing(Publishing.newBuilder() + .setRetryPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(3) + .setInitialBackoff(1) + .setMaxBackoff(4) + .setBackoffMultiplier(2) + .build()) + .setCompressBodyThreshold(4 * 1024) + .setMaxBodySize(4 * 1024 * 1024) + .build()) + .build(); + private static final Settings DEFAULT_CONSUMER_SETTINGS = Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setFifo(false) + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(16) + .setInitialBackoff(1) + .setMaxBackoff(10) + .setBackoffMultiplier(2) + .build()) + .setReceiveBatchSize(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) + .setLongPollingTimeout(Durations.fromSeconds(30)) + .build()) + .build(); private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); public Settings getClientSettings(Context ctx) { @@ -37,6 +67,11 @@ public class GrpcClientManager { } public void updateClientSettings(String clientId, Settings settings) { + if (settings.hasPublishing()) { + settings = DEFAULT_PRODUCER_SETTINGS.toBuilder().mergeFrom(settings).build(); + } else if (settings.hasSubscription()) { + settings = DEFAULT_CONSUMER_SETTINGS.toBuilder().mergeFrom(settings).build(); + } CLIENT_SETTINGS_MAP.put(clientId, settings); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 819349ede5..e0ebe9658f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -124,8 +124,7 @@ public class ConsumerService extends BaseService { protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - // TODO: get fifo config from subscriptionGroupManager - boolean fifo = false; + boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } From c2059179ec3e62ee613bfa29c42de9052217d6b3 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sun, 24 Apr 2022 11:34:02 +0800 Subject: [PATCH 122/338] [ISSUE #3949] v2 support --- distribution/bin/mqproxy | 45 +++++++++++++++++ .../rocketmq/proxy/config/ProxyConfig.java | 13 ++++- .../rocketmq/proxy/grpc/GrpcServer.java | 49 +++++++++++++------ 3 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 distribution/bin/mqproxy diff --git a/distribution/bin/mqproxy b/distribution/bin/mqproxy new file mode 100644 index 0000000000..9f0cb84ea0 --- /dev/null +++ b/distribution/bin/mqproxy @@ -0,0 +1,45 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [ -z "$ROCKETMQ_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + ROCKETMQ_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + ROCKETMQ_HOME=`cd "$ROCKETMQ_HOME" && pwd` + + cd "$saveddir" +fi + +export ROCKETMQ_HOME + +sh ${ROCKETMQ_HOME}/bin/runserver.sh org.apache.rocketmq.proxy.ProxyStartup $@ 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 a5da3cdae0..fbaf931556 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 @@ -43,8 +43,9 @@ public class ProxyConfig { private String proxyMode = ProxyMode.CLUSTER.name(); private Boolean startGrpcServer = true; private Integer grpcServerPort = 8081; - private String grpcTlsKeyPath = ConfigurationManager.getProxyHome() + "/conf/tls/gRPC.key.pem"; - private String grpcTlsCertPath = ConfigurationManager.getProxyHome() + "/conf/tls/gRPC.chain.cert.pem"; + private boolean grpcTlsTestModeEnable = true; + private String grpcTlsKeyPath = ConfigurationManager.getProxyHome() + "/conf/tls/rocketmq.key"; + private String grpcTlsCertPath = ConfigurationManager.getProxyHome() + "/conf/tls/rocketmq.crt"; private int grpcBossLoopNum = 1; private int grpcWorkerLoopNum = Runtime.getRuntime().availableProcessors() * 2; private boolean enableGrpcEpoll = false; @@ -165,6 +166,14 @@ public class ProxyConfig { this.grpcServerPort = grpcServerPort; } + public boolean isGrpcTlsTestModeEnable() { + return grpcTlsTestModeEnable; + } + + public void setGrpcTlsTestModeEnable(boolean grpcTlsTestModeEnable) { + this.grpcTlsTestModeEnable = grpcTlsTestModeEnable; + } + public String getGrpcTlsKeyPath() { return grpcTlsKeyPath; } 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 484e926de6..eca8012811 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 @@ -24,14 +24,16 @@ import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel; import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup; import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.security.cert.CertificateException; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLException; import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; @@ -40,6 +42,7 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; @@ -58,19 +61,9 @@ public class GrpcServer implements StartAndShutdown { int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(port); - // add tls files - String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); - String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); try { - InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); - InputStream serverCertificateStream = new FileInputStream(tlsCertPath); - - SslContext sslContext = GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .clientAuth(ClientAuth.NONE) - .build(); - serverBuilder.sslContext(sslContext); - } catch (IOException e) { + configSslContext(serverBuilder); + } catch (Exception e) { log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); throw new RuntimeException("grpc tls set failed: " + e.getMessage()); } @@ -125,10 +118,38 @@ public class GrpcServer implements StartAndShutdown { log.info( "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", - port, tlsKeyPath, tlsCertPath, threadPoolNums, threadPoolQueueCapacity, + port, threadPoolNums, threadPoolQueueCapacity, bossLoopNum, workerLoopNum, maxInboundMessageSize); } + protected void configSslContext(NettyServerBuilder serverBuilder) throws SSLException, CertificateException { + if (null == serverBuilder) { + return; + } + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + boolean tlsTestModeEnable = proxyConfig.isGrpcTlsTestModeEnable(); + if (tlsTestModeEnable) { + SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + serverBuilder.sslContext(GrpcSslContexts.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .clientAuth(ClientAuth.NONE) + .build()); + return; + } + + String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); + String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); + try (InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); + InputStream serverCertificateStream = new FileInputStream(tlsCertPath)) { + serverBuilder.sslContext(GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .clientAuth(ClientAuth.NONE) + .build()); + log.info("TLS configured OK"); + } catch (IOException e) { + log.error("Failed to load Server key/certificate", e); + } + } public void start() throws Exception { // first to start grpc service. From b8c3cbcc6e40a27288c5c4074ec73deb7328956f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sun, 24 Apr 2022 11:42:02 +0800 Subject: [PATCH 123/338] [ISSUE #3949] v2 support --- distribution/bin/mqproxy.cmd | 23 +++++++++++++++++++++++ distribution/bin/mqshutdown | 16 +++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 distribution/bin/mqproxy.cmd diff --git a/distribution/bin/mqproxy.cmd b/distribution/bin/mqproxy.cmd new file mode 100644 index 0000000000..d5f58e4de3 --- /dev/null +++ b/distribution/bin/mqproxy.cmd @@ -0,0 +1,23 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +if not exist "%ROCKETMQ_HOME%\bin\runserver.cmd" echo Please set the ROCKETMQ_HOME variable in your environment! & EXIT /B 1 + +call "%ROCKETMQ_HOME%\bin\runserver.cmd" org.apache.rocketmq.proxy.ProxyStartup %* + +IF %ERRORLEVEL% EQU 0 ( + ECHO "Proxy starts OK" +) \ No newline at end of file diff --git a/distribution/bin/mqshutdown b/distribution/bin/mqshutdown index d91fce9c5b..7ea6048e15 100644 --- a/distribution/bin/mqshutdown +++ b/distribution/bin/mqshutdown @@ -58,6 +58,20 @@ case $1 in echo "Send shutdown request to mqnamesrv(${pid}) OK" ;; + proxy) + + pid=`ps ax | grep -i 'org.apache.rocketmq.proxy.ProxyStartup' |grep java | grep -v grep | awk '{print $1}'` + if [ -z "$pid" ] ; then + echo "No mqproxy running." + exit -1; + fi + + echo "The mqproxy(${pid}) is running..." + + kill ${pid} + + echo "Send shutdown request to mqproxy(${pid}) OK" + ;; *) - echo "Useage: mqshutdown broker | namesrv" + echo "Useage: mqshutdown broker | namesrv | proxy" esac From 34749eafe5135333949daccd39ff1a49eb4d79f3 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sun, 24 Apr 2022 16:15:21 +0800 Subject: [PATCH 124/338] [ISSUE #3949] v2 support --- distribution/pom.xml | 4 ++ .../rocketmq/proxy/HealthCheckServer.java | 61 ------------------- .../apache/rocketmq/proxy/ProxyStartup.java | 7 +-- .../rocketmq/proxy/config/ProxyConfig.java | 43 +------------ .../factory/ForwardClientManager.java | 6 +- .../proxy/grpc/v1/adapter/GrpcConverter.java | 4 +- .../proxy/grpc/v2/GrpcMessagingProcessor.java | 3 +- .../proxy/grpc/v2/adapter/GrpcConverter.java | 31 +++++++--- .../proxy/grpc/v2/adapter/ResponseWriter.java | 14 ++++- .../grpc/v2/service/ClusterGrpcService.java | 6 +- .../grpc/v2/service/GrpcClientManager.java | 18 ++++-- .../grpc/v2/service/GrpcForwardService.java | 3 +- .../v2/service/cluster/ConsumerService.java | 49 +++++++++------ .../cluster/DefaultWriteQueueSelector.java | 34 ++++------- .../v2/service/cluster/ProducerService.java | 32 +++++----- .../service/cluster/WriteQueueSelector.java | 6 +- .../service/cluster/ConsumerServiceTest.java | 11 ++-- .../DefaultWriteQueueSelectorTest.java | 50 +-------------- .../service/cluster/ProducerServiceTest.java | 8 +-- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 42 +++++-------- 20 files changed, 159 insertions(+), 273 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java diff --git a/distribution/pom.xml b/distribution/pom.xml index 439e47790f..f50250b1ac 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -38,6 +38,10 @@ org.apache.rocketmq rocketmq-broker + + org.apache.rocketmq + rocketmq-proxy + org.apache.rocketmq rocketmq-client diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java deleted file mode 100644 index 2a6985c611..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/HealthCheckServer.java +++ /dev/null @@ -1,61 +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.proxy; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.time.Duration; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.config.ConfigurationManager; - -public class HealthCheckServer implements StartAndShutdown { - - private HttpServer healthChecker; - - @Override - public void start() throws Exception { - this.healthChecker = HttpServer.create( - new InetSocketAddress(ConfigurationManager.getProxyConfig().getHealthCheckPort()), 0 - ); - this.healthChecker.createContext("/status", new HealthCheckHandler()); - this.healthChecker.setExecutor(null); - this.healthChecker.start(); - } - - @Override - public void shutdown() throws InterruptedException { - this.healthChecker.stop(0); - long waitAfterStopHealthCheckInSeconds = ConfigurationManager.getProxyConfig().getWaitAfterStopHealthCheckInSeconds(); - Thread.sleep(Duration.ofSeconds(waitAfterStopHealthCheckInSeconds).toMillis()); - } - - static class HealthCheckHandler implements HttpHandler { - @Override - public void handle(HttpExchange t) throws IOException { - String response = "Hello"; - t.sendResponseHeaders(200, response.length()); - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); - } - } -} \ No newline at end of file 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 a4b1371de9..55f7526e58 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -63,10 +63,6 @@ public class ProxyStartup { GrpcServer grpcServer = createGrpcServer(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); - // create health check server - final HealthCheckServer healthCheckServer = new HealthCheckServer(); - PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(healthCheckServer); - // start servers one by one. PROXY_START_AND_SHUTDOWN.start(); @@ -86,7 +82,7 @@ public class ProxyStartup { } System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); - log.info(new Date() + "rmq-proxy startup successfully"); + log.info(new Date() + " rmq-proxy startup successfully"); } private static GrpcServer createGrpcServer() throws Exception { @@ -128,6 +124,7 @@ public class ProxyStartup { } private static void initLogger() throws JoranException { + System.setProperty("brokerLogDir", ""); System.setProperty(ClientLogger.CLIENT_LOG_USESLF4J, "true"); LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 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 fbaf931556..d4625cf149 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 @@ -22,19 +22,13 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; - /** - * Configuration for proxy - */ - private Integer healthCheckPort = 8000; - private long waitAfterStopHealthCheckInSeconds = 40; - /** * configuration for ThreadPoolMonitor */ private boolean enablePrintJstack = true; private long printJstackInMillis = 60000; - private String nameSrvAddr = "11.165.223.199:9876"; + private String nameSrvAddr = ""; private String nameSrvDomain = ""; private String nameSrvDomainSubgroup = ""; /** @@ -81,27 +75,8 @@ public class ProxyConfig { private long longPollingReserveTimeInMillis = 10000; - private int retryDelayLevelDelta = 2; - private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; - private boolean enableACL = false; - public Integer getHealthCheckPort() { - return healthCheckPort; - } - - public void setHealthCheckPort(Integer healthCheckPort) { - this.healthCheckPort = healthCheckPort; - } - - public long getWaitAfterStopHealthCheckInSeconds() { - return waitAfterStopHealthCheckInSeconds; - } - - public void setWaitAfterStopHealthCheckInSeconds(long waitAfterStopHealthCheckInSeconds) { - this.waitAfterStopHealthCheckInSeconds = waitAfterStopHealthCheckInSeconds; - } - public boolean isEnablePrintJstack() { return enablePrintJstack; } @@ -390,22 +365,6 @@ public class ProxyConfig { this.longPollingReserveTimeInMillis = longPollingReserveTimeInMillis; } - public int getRetryDelayLevelDelta() { - return retryDelayLevelDelta; - } - - public void setRetryDelayLevelDelta(int retryDelayLevelDelta) { - this.retryDelayLevelDelta = retryDelayLevelDelta; - } - - public String getMessageDelayLevel() { - return messageDelayLevel; - } - - public void setMessageDelayLevel(String messageDelayLevel) { - this.messageDelayLevel = messageDelayLevel; - } - public boolean isEnableACL() { return enableACL; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index fb8c12505c..3cc7b8ffcc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -49,7 +49,11 @@ public class ForwardClientManager implements StartAndShutdown { System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvDomain())) { - System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, ConfigurationManager.getProxyConfig().getNameSrvAddr()); + String nameSrvAddr = ConfigurationManager.getProxyConfig().getNameSrvAddr(); + if (StringUtils.isEmpty(nameSrvAddr)) { + throw new IllegalArgumentException("the address of namesrv cannot be empty"); + } + System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, nameSrvAddr); } else { System.setProperty("rocketmq.namesrv.domain", ConfigurationManager.getProxyConfig().getNameSrvDomain()); System.setProperty("rocketmq.namesrv.domain.subgroup", ConfigurationManager.getProxyConfig().getNameSrvDomainSubgroup()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java index cf832205e8..670ff95749 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java @@ -199,8 +199,8 @@ public class GrpcConverter { changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime( - delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); +// changeInvisibleTimeRequestHeader.setInvisibleTime( +// delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); return changeInvisibleTimeRequestHeader; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index 53f9fecfde..6317cddae3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -44,6 +44,7 @@ import apache.rocketmq.v2.Status; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.util.Iterator; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; @@ -116,7 +117,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.receiveMessage(Context.current(), request); + CompletableFuture> future = grpcForwardService.receiveMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 7b7269a378..9425d5b64f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -25,6 +25,7 @@ import apache.rocketmq.v2.Digest; import apache.rocketmq.v2.DigestType; import apache.rocketmq.v2.Encoding; import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.ExponentialBackoff; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -36,6 +37,7 @@ import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.SubscriptionEntry; @@ -158,11 +160,9 @@ public class GrpcConverter { } public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, - String producerGroup) { + String producerGroup, int queueId) { SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); - MessageQueue messageQueue = request.getMessageQueue(); - if (request.getMessagesCount() <= 0) { throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } @@ -177,7 +177,7 @@ public class GrpcConverter { requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); requestHeader.setDefaultTopic(""); requestHeader.setDefaultTopicQueueNums(0); - requestHeader.setQueueId(messageQueue.getId()); + requestHeader.setQueueId(queueId); // sysFlag (body encoding & message type) int sysFlag = 0; Encoding bodyEncoding = systemProperties.getBodyEncoding(); @@ -257,7 +257,7 @@ public class GrpcConverter { } public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, - DelayPolicy delayPolicy) { + RetryPolicy retryPolicy) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); @@ -269,10 +269,24 @@ public class GrpcConverter { changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); changeInvisibleTimeRequestHeader.setInvisibleTime( - delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); + Durations.toMillis(calculateNextDeliveryDurations(retryPolicy, request.getDeliveryAttempt()))); return changeInvisibleTimeRequestHeader; } + public static Duration calculateNextDeliveryDurations(RetryPolicy retryPolicy, int deliveryAttempt) { + if (retryPolicy.hasCustomizedBackoff()) { + int nextCount = retryPolicy.getCustomizedBackoff().getNextCount(); + return retryPolicy.getCustomizedBackoff().getNext(Math.min(nextCount, deliveryAttempt)); + } + ExponentialBackoff exponentialBackoff = retryPolicy.getExponentialBackoff(); + long nextDurationMillis = (long) (Math.pow(exponentialBackoff.getMultiplier(), deliveryAttempt) * + Durations.toMillis(exponentialBackoff.getInitial())); + nextDurationMillis = Math.min( + Durations.toMillis(exponentialBackoff.getMax()), + nextDurationMillis); + return Durations.fromMillis(nextDurationMillis); + } + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); @@ -430,9 +444,12 @@ public class GrpcConverter { } public static List buildMessage(List protoMessageList, - String producerGroup) { + Resource topic, String producerGroup) { List messages = new ArrayList<>(); for (Message protoMessage : protoMessageList) { + if (!protoMessage.getTopic().equals(topic)) { + throw new ProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); + } messages.add(buildMessage(protoMessage, producerGroup)); } return messages; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 11f4416633..25ad9feee6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; +import java.util.Iterator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -26,7 +27,19 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + public static void write(StreamObserver observer, final Iterator responseIterator) { + while (responseIterator.hasNext()) { + writeResponse(observer, responseIterator.next()); + } + observer.onCompleted(); + } + public static void write(StreamObserver observer, final T response) { + writeResponse(observer, response); + observer.onCompleted(); + } + + public static void writeResponse(StreamObserver observer, final T response) { if (observer instanceof ServerCallStreamObserver) { if (response == null) { return; @@ -40,7 +53,6 @@ public class ResponseWriter { log.debug("start to write response. response: {}", response); serverCallStreamObserver.onNext(response); - serverCallStreamObserver.onCompleted(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 6cd445ed60..697a663826 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -42,6 +42,8 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.util.Iterator; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -117,8 +119,8 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc } @Override - public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return consumerService.receiveMessage(ctx, request); + public CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { + return consumerService.receiveMessage(ctx, request).thenApply(List::iterator); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index f784c7fe29..b73e902c4c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc.v2.service; +import apache.rocketmq.v2.ExponentialBackoff; import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; @@ -30,13 +31,16 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { + // TODO: read config from topic or subscription configManager private static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() .setPublishing(Publishing.newBuilder() .setRetryPolicy(RetryPolicy.newBuilder() .setMaxAttempts(3) - .setInitialBackoff(1) - .setMaxBackoff(4) - .setBackoffMultiplier(2) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setInitial(Durations.fromSeconds(1)) + .setMax(Durations.fromSeconds(3)) + .setMultiplier(2) + .build()) .build()) .setCompressBodyThreshold(4 * 1024) .setMaxBodySize(4 * 1024 * 1024) @@ -47,9 +51,11 @@ public class GrpcClientManager { .setFifo(false) .setBackoffPolicy(RetryPolicy.newBuilder() .setMaxAttempts(16) - .setInitialBackoff(1) - .setMaxBackoff(10) - .setBackoffMultiplier(2) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setInitial(Durations.fromSeconds(5)) + .setMax(Durations.fromMinutes(30)) + .setMultiplier(2) + .build()) .build()) .setReceiveBatchSize(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) .setLongPollingTimeout(Durations.fromSeconds(30)) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java index f7bf6f946a..b1c984defe 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java @@ -42,6 +42,7 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.util.Iterator; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -55,7 +56,7 @@ public interface GrpcForwardService extends StartAndShutdown { CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request); + CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request); CompletableFuture nackMessage(Context ctx, NackMessageRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index e0ebe9658f..3cb4567e24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -30,6 +30,7 @@ import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; @@ -48,9 +49,7 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHead import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.FilterUtils; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; @@ -64,7 +63,6 @@ import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { - private final DelayPolicy delayPolicy; private final ForwardReadConsumer readConsumer; private final ForwardWriteConsumer writeConsumer; /** @@ -73,7 +71,7 @@ public class ConsumerService extends BaseService { private final ForwardProducer producer; private volatile ReadQueueSelector readQueueSelector; - private volatile ResponseHook receiveMessageHook; + private volatile ResponseHook> receiveMessageHook; private volatile ResponseHook ackNoMatchedMessageHook; private volatile ResponseHook forwardToDLQInRecvMessageHook; private volatile ResponseHook ackMessageHook; @@ -89,13 +87,12 @@ public class ConsumerService extends BaseService { this.producer = connectorManager.getForwardProducer(); this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); - this.delayPolicy = DelayPolicy.build(ConfigurationManager.getProxyConfig().getMessageDelayLevel()); this.grpcClientManager = grpcClientManager; } - public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); + public CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { + CompletableFuture> future = new CompletableFuture<>(); try { PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); @@ -128,27 +125,40 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } - protected ReceiveMessageResponse convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, + protected List convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, PopResult result) { + List responseList = new ArrayList<>(); PopStatus status = result.getPopStatus(); switch (status) { case FOUND: List messageList = filterMessage(ctx, request, result.getMsgFoundList()); - return ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllMessages(messageList) - .build(); + if (messageList.isEmpty()) { + responseList.add(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + } else { + for (Message message : messageList) { + responseList.add(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setMessage(message) + .build()); + } + } + break; case POLLING_FULL: - return ReceiveMessageResponse.newBuilder() + responseList.add(ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build(); + .build()); + break; case NO_NEW_MSG: case POLLING_NOT_FOUND: default: - return ReceiveMessageResponse.newBuilder() + responseList.add(ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build(); + .build()); + break; } + return responseList; } protected List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { @@ -360,7 +370,8 @@ public class ConsumerService extends BaseService { protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, this.delayPolicy); + RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy(); + return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, retryPolicy); } protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, NackMessageRequest request) { @@ -440,12 +451,12 @@ public class ConsumerService extends BaseService { this.readQueueSelector = readQueueSelector; } - public ResponseHook getReceiveMessageHook() { + public ResponseHook> getReceiveMessageHook() { return receiveMessageHook; } public void setReceiveMessageHook( - ResponseHook receiveMessageHook) { + ResponseHook> receiveMessageHook) { this.receiveMessageHook = receiveMessageHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java index f11dc142c0..0e11112912 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java @@ -16,18 +16,18 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; -import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; public class DefaultWriteQueueSelector implements WriteQueueSelector { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -41,26 +41,20 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { @Override public SelectableMessageQueue selectQueue( Context ctx, - SendMessageRequest request, - SendMessageRequestHeader requestHeader, - List messageList + SendMessageRequest request ) { try { - String topic = requestHeader.getTopic(); - String brokerName = ""; - if (request.hasMessageQueue()) { - brokerName = request.getMessageQueue().getBroker().getName(); + if (request.getMessagesCount() <= 0) { + throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } - Integer queueId = requestHeader.getQueueId(); + Message message = request.getMessages(0); + String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); String shardingKey = null; - if (messageList.size() == 1) { - shardingKey = messageList.get(0).getProperty(MessageConst.PROPERTY_SHARDING_KEY); + if (request.getMessagesCount() == 1) { + shardingKey = message.getSystemProperties().getMessageGroup(); } SelectableMessageQueue targetMessageQueue; - if (StringUtils.isNotBlank(brokerName) && queueId != null) { - // Grpc client sendSelect situation - targetMessageQueue = selectTargetQueue(topic, brokerName, queueId); - } else if (shardingKey != null) { + if (StringUtils.isNotEmpty(shardingKey)) { // With shardingKey targetMessageQueue = selectOrderQueue(topic, shardingKey); } else { @@ -77,10 +71,6 @@ public class DefaultWriteQueueSelector implements WriteQueueSelector { return this.topicRouteCache.selectOneWriteQueue(topic, null); } - protected SelectableMessageQueue selectTargetQueue(String topic, String brokerName, int queueId) throws Exception { - return this.topicRouteCache.selectOneWriteQueue(topic, brokerName, queueId); - } - protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { return this.topicRouteCache.selectOneWriteQueueByKey(topic, shardingKey); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 55d6fe5bf7..3bd711c194 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SendReceipt; @@ -27,7 +28,6 @@ import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; @@ -73,22 +73,17 @@ public class ProducerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); try { - Pair> requestPair = this.buildSendMessageRequest(ctx, request); - SendMessageRequestHeader requestHeader = requestPair.getLeft(); - List message = requestPair.getRight(); - SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request, requestHeader, message); - - String topic = requestHeader.getTopic(); + SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request); if (selectableMessageQueue == null) { - throw new ProxyException(Code.FORBIDDEN, "no writeable topic route for topic: " + topic); + throw new ProxyException(Code.FORBIDDEN, "no writeable topic route"); } // send message to broker. future = this.producer.sendMessage( selectableMessageQueue.getBrokerAddr(), selectableMessageQueue.getBrokerName(), - message, - requestHeader + convertToMessageList(ctx, request), + convertToSendMessageRequestHeader(ctx, request, selectableMessageQueue) ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); @@ -102,13 +97,18 @@ public class ProducerService extends BaseService { return future; } - protected Pair> buildSendMessageRequest( - Context ctx, SendMessageRequest request) { - String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + protected SendMessageRequestHeader convertToSendMessageRequestHeader(Context ctx, SendMessageRequest request, SelectableMessageQueue selectableMessageQueue) { // use topic name as group - SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topic); - List message = GrpcConverter.buildMessage(request.getMessagesList(), topic); - return Pair.of(requestHeader, message); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessages(0).getTopic()); + return GrpcConverter.buildSendMessageRequestHeader(request, topicName, + selectableMessageQueue.getQueueId()); + } + + protected List convertToMessageList(Context ctx, SendMessageRequest request) { + // use topic name as group + Resource topic = request.getMessages(0).getTopic(); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + return GrpcConverter.buildMessage(request.getMessagesList(), topic, topicName); } protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java index 929cab738c..90648fe2cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java @@ -18,13 +18,9 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.SendMessageRequest; import io.grpc.Context; -import java.util.List; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; public interface WriteQueueSelector { - SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request, - SendMessageRequestHeader requestHeader, List messageList); + SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 12e7fb838f..5d993ee4f0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -85,7 +85,7 @@ public class ConsumerServiceTest extends BaseServiceTest { Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); AtomicReference ackHandler = new AtomicReference<>(); consumerService.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); - ReceiveMessageResponse response = consumerService.receiveMessage(ctx, + List responseList = consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setTopic(Resource.newBuilder() @@ -100,9 +100,10 @@ public class ConsumerServiceTest extends BaseServiceTest { .build() ).get(); + assertEquals(1, responseList.size()); + ReceiveMessageResponse response = responseList.get(0); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(1, response.getMessagesCount()); - assertEquals("msg1", response.getMessages(0).getSystemProperties().getMessageId()); + assertEquals("msg1", response.getMessage().getSystemProperties().getMessageId()); assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); } @@ -137,7 +138,7 @@ public class ConsumerServiceTest extends BaseServiceTest { }).when(producerClient).sendMessageBackThenAckOrg(anyString(), any(), any()); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); - ReceiveMessageResponse response = consumerService.receiveMessage(ctx, + List responseList = consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setTopic(Resource.newBuilder() @@ -152,6 +153,8 @@ public class ConsumerServiceTest extends BaseServiceTest { .build() ).get(); + assertEquals(1, responseList.size()); + ReceiveMessageResponse response = responseList.get(0); assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(2, toDLQMsgId.size()); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java index b68d935530..a63561d7f3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java @@ -1,6 +1,5 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.Broker; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; @@ -8,22 +7,17 @@ import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.ByteString; import io.grpc.Context; import java.nio.charset.StandardCharsets; -import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; public class DefaultWriteQueueSelectorTest extends BaseServiceTest { - private static final String TOPIC_NAME = "namespace%topic"; - @Override public void beforeEach() throws Throwable { SelectableMessageQueue queue = new SelectableMessageQueue( @@ -32,12 +26,6 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString())) .thenReturn(queue); - queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectTargetQueue", 0), - "selectTargetQueueAddr"); - when(topicRouteCache.selectOneWriteQueue(anyString(), anyString(), anyInt())) - .thenReturn(queue); - queue = new SelectableMessageQueue( new MessageQueue("topic", "selectNormalQueue", 0), "selectNormalQueueAddr"); @@ -53,17 +41,15 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .setResourceNamespace("namespace") .setName("topic") .build()) - .putUserProperties(MessageConst.PROPERTY_SHARDING_KEY, "key") .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") + .setMessageGroup("key") .build()) .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), - GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); assertEquals("selectOrderQueue", queue.getBrokerName()); assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); @@ -84,39 +70,9 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .build()) .build(); WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), - GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); + SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); assertEquals("selectNormalQueue", queue.getBrokerName()); assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); } - - @Test - public void selectTargetQueue() { - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() - .setBroker(Broker.newBuilder() - .setName("brokerName") - .build()) - .build()) - .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request, - GrpcConverter.buildSendMessageRequestHeader(request, TOPIC_NAME), - GrpcConverter.buildMessage(request.getMessagesList(), TOPIC_NAME)); - - assertEquals("selectTargetQueue", queue.getBrokerName()); - assertEquals("selectTargetQueueAddr", queue.getBrokerAddr()); - } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 727150fc67..566f0c763b 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -72,7 +72,7 @@ public class ProducerServiceTest extends BaseServiceTest { 1L, "txId", "offsetMsgId", "regionId")); ProducerService producerService = new ProducerService(this.connectorManager); - producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> + producerService.setWriteQueueSelector((ctx, request) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); @@ -90,7 +90,7 @@ public class ProducerServiceTest extends BaseServiceTest { public void testSendMessageNoQueueSelect() { ProducerService producerService = new ProducerService(this.connectorManager); - producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> null); + producerService.setWriteQueueSelector((ctx, request) -> null); CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() .addMessages(Message.newBuilder() @@ -126,7 +126,7 @@ public class ProducerServiceTest extends BaseServiceTest { sendResultFuture.completeExceptionally(ex); ProducerService producerService = new ProducerService(this.connectorManager); - producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> + producerService.setWriteQueueSelector((ctx, request) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); @@ -146,7 +146,7 @@ public class ProducerServiceTest extends BaseServiceTest { RuntimeException ex = new RuntimeException(); ProducerService producerService = new ProducerService(this.connectorManager); - producerService.setWriteQueueSelector((ctx, request, requestHeader, message) -> { + producerService.setWriteQueueSelector((ctx, request) -> { throw ex; }); producerService.setSendMessageHook((ctx, request, response, t) -> { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 97e714f49e..2fdd10e459 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -81,7 +81,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -226,7 +225,7 @@ public class GrpcBaseTest extends BaseConf { ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(response, messageId); - String receiptHandle = response.getMessages(0).getSystemProperties().getReceiptHandle(); + String receiptHandle = response.getMessage().getSystemProperties().getReceiptHandle(); AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, messageId, receiptHandle)); assertAllAckOk(ackMessageResponse); } @@ -249,7 +248,7 @@ public class GrpcBaseTest extends BaseConf { ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(receiveResponse, messageId); - Message message = receiveResponse.getMessages(0); + Message message = receiveResponse.getMessage(); NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 1 )); @@ -258,15 +257,15 @@ public class GrpcBaseTest extends BaseConf { AtomicReference receiveRetryResponseRef = new AtomicReference<>(); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group, 1).get(0); - if (receiveRetryResponse.getMessagesCount() <= 0) { + if (!receiveRetryResponse.hasMessage()) { return false; } receiveRetryResponseRef.set(receiveRetryResponse); - return receiveRetryResponse.getMessages(0).getSystemProperties() + return receiveRetryResponse.getMessage().getSystemProperties() .getMessageId().equals(messageId); }); - message = receiveRetryResponseRef.get().getMessages(0); + message = receiveRetryResponseRef.get().getMessage(); nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 2 )); @@ -363,10 +362,10 @@ public class GrpcBaseTest extends BaseConf { await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); - if (receiveRetryResponse.getMessagesCount() <= 0) { + if (!receiveRetryResponse.hasMessage()) { return false; } - return receiveRetryResponse.getMessages(0).getSystemProperties() + return receiveRetryResponse.getMessage().getSystemProperties() .getMessageId().equals(messageId); }); } finally { @@ -394,7 +393,7 @@ public class GrpcBaseTest extends BaseConf { ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemProperties().getReceiptHandle(); + String receiptHandle = receiveResponse.getMessage().getSystemProperties().getReceiptHandle(); ChangeInvisibleDurationResponse changeResponse = blockingStub.changeInvisibleDuration(buildChangeInvisibleDurationRequest(topic, group, receiptHandle, 5)); assertChangeInvisibleDurationResponse(changeResponse, receiptHandle); @@ -403,12 +402,12 @@ public class GrpcBaseTest extends BaseConf { await().atMost(java.time.Duration.ofSeconds(20)).until(() -> { ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); - if (receiveRetryResponse.getMessagesCount() <= 0) { + if (!receiveRetryResponse.hasMessage()) { return false; } - if (receiveRetryResponse.getMessages(0).getSystemProperties() + if (receiveRetryResponse.getMessage().getSystemProperties() .getMessageId().equals(messageId)) { - ackHandles.add(receiveRetryResponse.getMessages(0).getSystemProperties().getReceiptHandle()); + ackHandles.add(receiveRetryResponse.getMessage().getSystemProperties().getReceiptHandle()); return true; } return false; @@ -461,8 +460,8 @@ public class GrpcBaseTest extends BaseConf { await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { try { ReceiveMessageResponse retryReceiveResponse = receiveMessage(blockingStub, topic, group, 1).get(0); - if (retryReceiveResponse.getMessagesCount() > 0) { - receiveMessageCount.addAndGet(retryReceiveResponse.getMessagesCount()); + if (retryReceiveResponse.hasMessage()) { + receiveMessageCount.incrementAndGet(); } PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); @@ -518,11 +517,6 @@ public class GrpcBaseTest extends BaseConf { public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { return SendMessageRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .build()) .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) @@ -541,11 +535,6 @@ public class GrpcBaseTest extends BaseConf { public SendMessageRequest buildTransactionSendMessageRequest(String topic, String messageId) { return SendMessageRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .build()) .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() .setName(topic) @@ -572,7 +561,7 @@ public class GrpcBaseTest extends BaseConf { .setTopic(Resource.newBuilder() .setName(topic) .build()) - .setId(0) + .setId(-1) .build()) .setBatchSize(16) .setInvisibleDuration(Duration.newBuilder() @@ -661,8 +650,7 @@ public class GrpcBaseTest extends BaseConf { public void assertReceiveMessage(ReceiveMessageResponse response, String messageId) { assertThat(response.getStatus() .getCode()).isEqualTo(Code.OK); - assertThat(response.getMessagesCount()).isEqualTo(1); - assertThat(response.getMessages(0) + assertThat(response.getMessage() .getSystemProperties() .getMessageId()).isEqualTo(messageId); } From 1cc1d1043431df54c673bd3999d9c51096c43ec2 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sun, 24 Apr 2022 20:40:29 +0800 Subject: [PATCH 125/338] [ISSUE #3949] v2 support --- pom.xml | 4 ++-- .../rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3362e6c84a..2f14a7bb45 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ ${project.basedir}/../test/target/jacoco-it.exec file:**/generated-sources/**,**/test/** - 1.38.0 + 1.45.0 @@ -668,7 +668,7 @@ com.google.protobuf protobuf-java-util - 3.19.4 + 3.20.1 diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index 5ae5abde19..994088bce6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -20,10 +20,15 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Status; import java.util.concurrent.CompletionException; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseBuilder { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + public static Status buildStatus(Throwable t) { if (t instanceof CompletionException) { t = t.getCause(); @@ -32,6 +37,7 @@ public class ResponseBuilder { ProxyException proxyException = (ProxyException) t; return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); } + log.error("internal server error", t); return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); } From c08fee78affef8a3ccd09bc8900aef1f2721a5ba Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Sun, 24 Apr 2022 19:11:03 +0800 Subject: [PATCH 126/338] [ISSUE #3949] do the code refactoring work for readability. --- .../java/org/apache/rocketmq/proxy/ProxyStartup.java | 2 +- .../rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java | 11 ++++++----- .../grpc/v2/service/cluster/ProducerService.java | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) 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 55f7526e58..516a99506a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -81,7 +81,7 @@ public class ProxyStartup { System.exit(1); } - System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); + System.out.println(new Date() + " rmq-proxy startup successfully"); log.info(new Date() + " rmq-proxy startup successfully"); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 9425d5b64f..d933b5e27d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -89,7 +89,6 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; @@ -444,22 +443,24 @@ public class GrpcConverter { } public static List buildMessage(List protoMessageList, - Resource topic, String producerGroup) { + Resource topic) { + String topicName = wrapResourceWithNamespace(topic); List messages = new ArrayList<>(); for (Message protoMessage : protoMessageList) { if (!protoMessage.getTopic().equals(topic)) { throw new ProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); } - messages.add(buildMessage(protoMessage, producerGroup)); + // here use topicName as producerGroup for transactional checker. + messages.add(buildMessage(protoMessage, topicName)); } return messages; } public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage, String producerGroup) { - String topic = wrapResourceWithNamespace(protoMessage.getTopic()); + String topicName = wrapResourceWithNamespace(protoMessage.getTopic()); org.apache.rocketmq.common.message.Message message = - new org.apache.rocketmq.common.message.Message(topic, protoMessage.getBody().toByteArray()); + new org.apache.rocketmq.common.message.Message(topicName, protoMessage.getBody().toByteArray()); Map messageProperty = buildMessageProperty(protoMessage, producerGroup); MessageAccessor.setProperties(message, messageProperty); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 3bd711c194..39136e36d6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -108,7 +108,7 @@ public class ProducerService extends BaseService { // use topic name as group Resource topic = request.getMessages(0).getTopic(); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - return GrpcConverter.buildMessage(request.getMessagesList(), topic, topicName); + return GrpcConverter.buildMessage(request.getMessagesList(), topic); } protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, From 25cea87253ff6f65984a0151799fb1734c8707ce Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 10:07:34 +0800 Subject: [PATCH 127/338] [ISSUE #3949] v2 support --- .../java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 2fdd10e459..0ba85b8109 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -148,12 +148,12 @@ public class GrpcBaseTest extends BaseConf { protected MessagingServiceGrpc.MessagingServiceStub createStub(Channel channel) { MessagingServiceGrpc.MessagingServiceStub stub = MessagingServiceGrpc.newStub(channel); - return MetadataUtils.attachHeaders(stub, header); + return stub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(header)); } protected MessagingServiceGrpc.MessagingServiceBlockingStub createBlockingStub(Channel channel) { MessagingServiceGrpc.MessagingServiceBlockingStub stub = MessagingServiceGrpc.newBlockingStub(channel); - return MetadataUtils.attachHeaders(stub, header); + return stub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(header)); } protected CompletableFuture sendClientSettings(MessagingServiceGrpc.MessagingServiceStub stub, From 8c41ccb0c43e2c50d508c51e74d9c4271870c6cc Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 14:10:37 +0800 Subject: [PATCH 128/338] [ISSUE #3949] v2 support --- .../proxy/channel/ChannelManager.java | 4 +- .../proxy/common/TelemetryCommandManager.java | 4 +- .../proxy/connector/ConnectorManager.java | 18 ++- .../factory/ForwardClientManager.java | 22 ++-- .../factory/TransactionProducerFactory.java | 2 +- .../proxy/grpc/v2/adapter/GrpcConverter.java | 49 +++++++ .../grpc/v2/service/ClusterGrpcService.java | 24 ++-- .../grpc/v2/service/GrpcClientManager.java | 6 +- .../v2/service/cluster/ConsumerService.java | 9 +- .../service/cluster/ForwardClientService.java | 13 +- .../v2/service/cluster/ProducerService.java | 41 ++++-- .../grpc/v2/service/cluster/RouteService.java | 124 +++++++----------- .../service/cluster/TransactionService.java | 12 +- .../v2/service/cluster/RouteServiceTest.java | 11 +- 14 files changed, 198 insertions(+), 141 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 29bb2d671b..925d923705 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -35,8 +35,8 @@ import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; public class ChannelManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); - private final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); + protected final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); + protected final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); public SimpleChannel createChannel() { return createChannel(anonymousChannelId()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java index 62c9be63d1..99461ed39b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java @@ -22,8 +22,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; public class TelemetryCommandManager { - private final ConcurrentMap commandTable = new ConcurrentHashMap<>(); - private final AtomicLong commandIdGenerator = new AtomicLong(0); + protected final ConcurrentMap commandTable = new ConcurrentHashMap<>(); + protected final AtomicLong commandIdGenerator = new AtomicLong(0); public String putCommand(int opaque) { String nonce = String.valueOf(commandIdGenerator.incrementAndGet()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java index 3965208d06..e0495c319e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java @@ -23,16 +23,20 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; public class ConnectorManager extends AbstractStartAndShutdown { - private final ForwardClientManager forwardClientManager; - private final DefaultForwardClient defaultForwardClient; - private final ForwardProducer forwardProducer; - private final ForwardReadConsumer forwardReadConsumer; - private final ForwardWriteConsumer forwardWriteConsumer; + protected ForwardClientManager forwardClientManager; + protected DefaultForwardClient defaultForwardClient; + protected ForwardProducer forwardProducer; + protected ForwardReadConsumer forwardReadConsumer; + protected ForwardWriteConsumer forwardWriteConsumer; - private final TopicRouteCache topicRouteCache; - private final TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; + protected TopicRouteCache topicRouteCache; + protected TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; public ConnectorManager(TransactionStateChecker transactionStateChecker) { + this.init(transactionStateChecker); + } + + protected void init(TransactionStateChecker transactionStateChecker) { this.forwardClientManager = new ForwardClientManager(transactionStateChecker); this.defaultForwardClient = new DefaultForwardClient(this.forwardClientManager); this.forwardProducer = new ForwardProducer(this.forwardClientManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index 3cc7b8ffcc..28bd923381 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -30,22 +30,16 @@ import org.apache.rocketmq.remoting.RPCHook; public class ForwardClientManager implements StartAndShutdown { - private RPCHook rpcHook; + protected RPCHook rpcHook; - private final MQClientFactory mqClientFactory; - private final TransactionProducerFactory transactionalProducerFactory; + protected MQClientFactory mqClientFactory; + protected TransactionProducerFactory transactionalProducerFactory; public ForwardClientManager(TransactionStateChecker transactionStateChecker) { - this.init(); - - ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat("ForwardClientFactoryScheduledThread" + "-%d").build() - ); - this.mqClientFactory = new MQClientFactory(scheduledExecutorService, this.rpcHook); - this.transactionalProducerFactory = new TransactionProducerFactory(scheduledExecutorService, this.rpcHook, transactionStateChecker); + this.init(transactionStateChecker); } - private void init() { + protected void init(TransactionStateChecker transactionStateChecker) { System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvDomain())) { @@ -58,6 +52,12 @@ public class ForwardClientManager implements StartAndShutdown { System.setProperty("rocketmq.namesrv.domain", ConfigurationManager.getProxyConfig().getNameSrvDomain()); System.setProperty("rocketmq.namesrv.domain.subgroup", ConfigurationManager.getProxyConfig().getNameSrvDomainSubgroup()); } + + ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder().setNameFormat("ForwardClientFactoryScheduledThread" + "-%d").build() + ); + this.mqClientFactory = new MQClientFactory(scheduledExecutorService, this.rpcHook); + this.transactionalProducerFactory = new TransactionProducerFactory(scheduledExecutorService, this.rpcHook, transactionStateChecker); } public MQClientAPIExt getMQClient(String instanceName, int bootstrapWorkerThreads) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java index 92a4006479..60234b3f84 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java @@ -23,7 +23,7 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.remoting.RPCHook; public class TransactionProducerFactory extends AbstractMQClientFactory { - private final TransactionStateChecker transactionStateChecker; + protected final TransactionStateChecker transactionStateChecker; public TransactionProducerFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index d933b5e27d..d8913cfedb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.Broker; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; @@ -35,6 +36,7 @@ import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.Permission; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.RetryPolicy; @@ -63,6 +65,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; @@ -85,6 +88,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.logging.InternalLogger; @@ -685,4 +689,49 @@ public class GrpcConverter { return pollTime; } + public static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { + List messageQueueList = new ArrayList<>(); + + int r = 0; + int w = 0; + int rw = 0; + if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { + rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); + r = queueData.getReadQueueNums() - rw; + w = queueData.getWriteQueueNums() - rw; + } else if (PermName.isWriteable(queueData.getPerm())) { + w = queueData.getWriteQueueNums(); + } else if (PermName.isReadable(queueData.getPerm())) { + r = queueData.getReadQueueNums(); + } + + // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. + int queueIdIndex = 0; + for (int i = 0; i < r; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ) + .build(); + messageQueueList.add(messageQueue); + } + + for (int i = 0; i < w; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.WRITE) + .build(); + messageQueueList.add(messageQueue); + } + + for (int i = 0; i < rw; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ_WRITE) + .build(); + messageQueueList.add(messageQueue); + } + + return messageQueueList; + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 697a663826..7dfd982981 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -68,21 +68,25 @@ import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") ); - private final ChannelManager channelManager; - private final ConnectorManager connectorManager; - private final ProducerService producerService; - private final ConsumerService consumerService; - private final RouteService routeService; - private final ForwardClientService clientService; - private final TransactionService transactionService; - private final TelemetryCommandManager pollCommandResponseManager; - private final GrpcClientManager grpcClientManager; + protected ChannelManager channelManager; + protected ConnectorManager connectorManager; + protected ProducerService producerService; + protected ConsumerService consumerService; + protected RouteService routeService; + protected ForwardClientService clientService; + protected TransactionService transactionService; + protected TelemetryCommandManager pollCommandResponseManager; + protected GrpcClientManager grpcClientManager; public ClusterGrpcService() { + this.init(); + } + + protected void init() { this.channelManager = new ChannelManager(); this.grpcClientManager = new GrpcClientManager(); this.pollCommandResponseManager = new TelemetryCommandManager(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index b73e902c4c..86eab3a26d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -32,7 +32,7 @@ import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; public class GrpcClientManager { // TODO: read config from topic or subscription configManager - private static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() + protected static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() .setPublishing(Publishing.newBuilder() .setRetryPolicy(RetryPolicy.newBuilder() .setMaxAttempts(3) @@ -46,7 +46,7 @@ public class GrpcClientManager { .setMaxBodySize(4 * 1024 * 1024) .build()) .build(); - private static final Settings DEFAULT_CONSUMER_SETTINGS = Settings.newBuilder() + protected static final Settings DEFAULT_CONSUMER_SETTINGS = Settings.newBuilder() .setSubscription(Subscription.newBuilder() .setFifo(false) .setBackoffPolicy(RetryPolicy.newBuilder() @@ -61,7 +61,7 @@ public class GrpcClientManager { .setLongPollingTimeout(Durations.fromSeconds(30)) .build()) .build(); - private static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); + protected static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); public Settings getClientSettings(Context ctx) { String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 3cb4567e24..3c9ac57364 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -63,12 +63,13 @@ import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { - private final ForwardReadConsumer readConsumer; - private final ForwardWriteConsumer writeConsumer; + protected final ForwardReadConsumer readConsumer; + protected final ForwardWriteConsumer writeConsumer; /** * For sending messages back to broker. */ - private final ForwardProducer producer; + protected final ForwardProducer producer; + protected final GrpcClientManager grpcClientManager; private volatile ReadQueueSelector readQueueSelector; private volatile ResponseHook> receiveMessageHook; @@ -78,8 +79,6 @@ public class ConsumerService extends BaseService { private volatile ResponseHook nackMessageHook; private volatile ResponseHook changeInvisibleDurationHook; - private final GrpcClientManager grpcClientManager; - public ConsumerService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { super(connectorManager); this.readConsumer = connectorManager.getForwardReadConsumer(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index e62b18a113..45b1d40705 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -58,12 +58,13 @@ import org.apache.rocketmq.remoting.protocol.LanguageCode; public class ForwardClientService extends BaseService { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ChannelManager channelManager; - private final ConsumerManager consumerManager; - private final ProducerManager producerManager; - private final GrpcClientManager grpcClientManager; - private final TelemetryCommandManager telemetryCommandManager; - private final ClientSettingsService clientSettingsService; + protected final ChannelManager channelManager; + protected final GrpcClientManager grpcClientManager; + protected final TelemetryCommandManager telemetryCommandManager; + + protected ConsumerManager consumerManager; + protected ProducerManager producerManager; + protected ClientSettingsService clientSettingsService; public ForwardClientService( ConnectorManager connectorManager, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 39136e36d6..d3f0e1c812 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -45,7 +45,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerService extends BaseService { - private final ForwardProducer producer; + protected final ForwardProducer producer; private volatile WriteQueueSelector writeQueueSelector; private volatile ResponseHook sendMessageHook; private volatile ResponseHook forwardMessageToDLQHook; @@ -56,19 +56,6 @@ public class ProducerService extends BaseService { writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); } - public void setSendMessageHook(ResponseHook sendMessageHook) { - this.sendMessageHook = sendMessageHook; - } - - public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { - this.writeQueueSelector = writeQueueSelector; - } - - public void setForwardMessageToDLQHook( - ResponseHook forwardMessageToDLQHook) { - this.forwardMessageToDLQHook = forwardMessageToDLQHook; - } - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); @@ -165,4 +152,30 @@ public class ProducerService extends BaseService { .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) .build(); } + + public WriteQueueSelector getWriteQueueSelector() { + return writeQueueSelector; + } + + public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { + this.writeQueueSelector = writeQueueSelector; + } + + public ResponseHook getSendMessageHook() { + return sendMessageHook; + } + + public void setSendMessageHook( + ResponseHook sendMessageHook) { + this.sendMessageHook = sendMessageHook; + } + + public ResponseHook getForwardMessageToDLQHook() { + return forwardMessageToDLQHook; + } + + public void setForwardMessageToDLQHook( + ResponseHook forwardMessageToDLQHook) { + this.forwardMessageToDLQHook = forwardMessageToDLQHook; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index a4db99b3a6..aba9cef649 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -28,7 +28,6 @@ import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; import com.google.common.base.Preconditions; import com.google.common.net.HostAndPort; @@ -38,7 +37,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; @@ -64,38 +62,18 @@ public class RouteService extends BaseService { private volatile AssignmentQueueSelector assignmentQueueSelector; private volatile ResponseHook queryAssignmentHook; - private GrpcClientManager grpcClientManager; + protected final GrpcClientManager grpcClientManager; public RouteService(ProxyMode mode, ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { super(connectorManager); Preconditions.checkArgument(ProxyMode.isClusterMode(mode) || ProxyMode.isLocalMode(mode)); this.mode = mode; - queryRouteEndpointConverter = (ctx, parameter) -> parameter; - queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; - assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); + this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; + this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; + this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); this.grpcClientManager = grpcClientManager; } - public void setQueryRouteEndpointConverter(ParameterConverter queryRouteEndpointConverter) { - this.queryRouteEndpointConverter = queryRouteEndpointConverter; - } - - public void setQueryRouteHook(ResponseHook queryRouteHook) { - this.queryRouteHook = queryRouteHook; - } - - public void setQueryAssignmentEndpointConverter(ParameterConverter queryAssignmentEndpointConverter) { - this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; - } - - public void setAssignmentQueueSelector(AssignmentQueueSelector assignmentQueueSelector) { - this.assignmentQueueSelector = assignmentQueueSelector; - } - - public void setQueryAssignmentHook(ResponseHook queryAssignmentHook) { - this.queryAssignmentHook = queryAssignmentHook; - } - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -129,7 +107,7 @@ public class RouteService extends BaseService { .setEndpoints(resEndpoints) .build(); - messageQueueList.addAll(genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); + messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); } } if (ProxyMode.isLocalMode(mode.name())) { @@ -142,7 +120,7 @@ public class RouteService extends BaseService { break; } for (Broker broker : brokerIdMap.values()) { - messageQueueList.addAll(genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); + messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); } } } @@ -164,51 +142,6 @@ public class RouteService extends BaseService { return future; } - protected static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { - List messageQueueList = new ArrayList<>(); - - int r = 0; - int w = 0; - int rw = 0; - if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { - rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); - r = queueData.getReadQueueNums() - rw; - w = queueData.getWriteQueueNums() - rw; - } else if (PermName.isWriteable(queueData.getPerm())) { - w = queueData.getWriteQueueNums(); - } else if (PermName.isReadable(queueData.getPerm())) { - r = queueData.getReadQueueNums(); - } - - // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. - int queueIdIndex = 0; - for (int i = 0; i < r; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ) - .build(); - messageQueueList.add(messageQueue); - } - - for (int i = 0; i < w; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.WRITE) - .build(); - messageQueueList.add(messageQueue); - } - - for (int i = 0; i < rw; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ_WRITE) - .build(); - messageQueueList.add(messageQueue); - } - - return messageQueueList; - } - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -311,4 +244,49 @@ public class RouteService extends BaseService { } return brokerMap; } + + public ParameterConverter getQueryRouteEndpointConverter() { + return queryRouteEndpointConverter; + } + + public void setQueryRouteEndpointConverter( + ParameterConverter queryRouteEndpointConverter) { + this.queryRouteEndpointConverter = queryRouteEndpointConverter; + } + + public ResponseHook getQueryRouteHook() { + return queryRouteHook; + } + + public void setQueryRouteHook( + ResponseHook queryRouteHook) { + this.queryRouteHook = queryRouteHook; + } + + public ParameterConverter getQueryAssignmentEndpointConverter() { + return queryAssignmentEndpointConverter; + } + + public void setQueryAssignmentEndpointConverter( + ParameterConverter queryAssignmentEndpointConverter) { + this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; + } + + public AssignmentQueueSelector getAssignmentQueueSelector() { + return assignmentQueueSelector; + } + + public void setAssignmentQueueSelector( + AssignmentQueueSelector assignmentQueueSelector) { + this.assignmentQueueSelector = assignmentQueueSelector; + } + + public ResponseHook getQueryAssignmentHook() { + return queryAssignmentHook; + } + + public void setQueryAssignmentHook( + ResponseHook queryAssignmentHook) { + this.queryAssignmentHook = queryAssignmentHook; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index 88bd809660..eea4722e0a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -42,8 +42,8 @@ import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { - private final ChannelManager channelManager; - private final ForwardProducer forwardProducer; + protected final ChannelManager channelManager; + protected final ForwardProducer forwardProducer; private volatile ResponseHook checkTransactionStateHook; private volatile ResponseHook endTransactionHook; @@ -115,11 +115,19 @@ public class TransactionService extends BaseService implements TransactionStateC return GrpcConverter.buildEndTransactionRequestHeader(request, topic); } + public ResponseHook getCheckTransactionStateHook() { + return checkTransactionStateHook; + } + public void setCheckTransactionStateHook( ResponseHook checkTransactionStateHook) { this.checkTransactionStateHook = checkTransactionStateHook; } + public ResponseHook getEndTransactionHook() { + return endTransactionHook; + } + public void setEndTransactionHook( ResponseHook endTransactionHook) { this.endTransactionHook = endTransactionHook; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 4d9cb69bce..e4e5e6fe4c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -43,6 +43,7 @@ import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.junit.Test; @@ -111,7 +112,7 @@ public class RouteServiceTest extends BaseServiceTest { public void testGenPartitionFromQueueData() throws Exception { // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. QueueData queueDataWith8R8WPermRW = mockQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R8WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); @@ -119,7 +120,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. QueueData queueDataWith8R8WPermR = mockQueueData(8, 8, PermName.PERM_READ); - List partitionWith8R8WPermR = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermR = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermR.size()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -127,7 +128,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. QueueData queueDataWith8R8WPermW = mockQueueData(8, 8, PermName.PERM_WRITE); - List partitionWith8R8WPermW = RouteService.genMessageQueueFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R8WPermW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R8WPermW.size()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(8); assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -135,7 +136,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. QueueData queueDataWith8R0WPermRW = mockQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R0WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith8R0WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith8R0WPermRW.size()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); @@ -143,7 +144,7 @@ public class RouteServiceTest extends BaseServiceTest { // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. QueueData queueDataWith4R8WPermRW = mockQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith4R8WPermRW = RouteService.genMessageQueueFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); + List partitionWith4R8WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); assertThat(partitionWith4R8WPermRW.size()).isEqualTo(8); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(4); assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(4); From c2fd34872b4728d2ac1be6ede80704cfcaf5ae3c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 14:32:33 +0800 Subject: [PATCH 129/338] [ISSUE #3949] v2 support --- .../proxy/connector/DefaultForwardClient.java | 11 ++++-- .../proxy/connector/ForwardProducer.java | 36 ++++++++++--------- .../proxy/connector/ForwardReadConsumer.java | 12 ++++--- .../proxy/connector/ForwardWriteConsumer.java | 11 ++++-- .../TransactionHeartbeatRegisterService.java | 4 ++- .../v2/service/cluster/ConsumerService.java | 13 ++++--- .../v2/service/cluster/ProducerService.java | 3 +- .../service/cluster/TransactionService.java | 2 +- .../service/cluster/ConsumerServiceTest.java | 20 +++++------ .../service/cluster/ProducerServiceTest.java | 4 +-- .../cluster/TransactionServiceTest.java | 6 ++-- 11 files changed, 72 insertions(+), 50 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java index 3cf8bd9334..ee7b1e45c7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector; +import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.exception.MQClientException; @@ -47,6 +48,7 @@ public class DefaultForwardClient extends AbstractForwardClient { } public CompletableFuture> getConsumerListByGroup( + Context ctx, String brokerAddr, GetConsumerListByGroupRequestHeader requestHeader, long timeoutMillis @@ -64,11 +66,12 @@ public class DefaultForwardClient extends AbstractForwardClient { return this.getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); } - public CompletableFuture getMaxOffset(String brokerAddr, String topic, int queueId) { - return this.getMaxOffset(brokerAddr, topic, queueId, DEFAULT_MQ_CLIENT_TIMEOUT); + public CompletableFuture getMaxOffset(Context ctx, String brokerAddr, String topic, int queueId) { + return this.getMaxOffset(ctx, brokerAddr, topic, queueId, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture getMaxOffset( + Context ctx, String brokerAddr, String topic, int queueId, @@ -78,15 +81,17 @@ public class DefaultForwardClient extends AbstractForwardClient { } public CompletableFuture searchOffset( + Context ctx, String brokerAddr, String topic, int queueId, long timestamp ) { - return this.searchOffset(brokerAddr, topic, queueId, timestamp, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.searchOffset(ctx, brokerAddr, topic, queueId, timestamp, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture searchOffset( + Context ctx, String brokerAddr, String topic, int queueId, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 355449ba7c..10202aa5b9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector; +import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.protocol.ResponseCode; @@ -54,31 +55,33 @@ public class ForwardProducer extends AbstractForwardClient { return clientFactory.getTransactionalProducer(name, threadCount); } - public CompletableFuture heartBeat(String brokerAddr, HeartbeatData heartbeatData) throws Exception { - return this.heartBeat(brokerAddr, heartbeatData, DEFAULT_MQ_CLIENT_TIMEOUT); + public CompletableFuture heartBeat(Context ctx, String brokerAddr, HeartbeatData heartbeatData) throws Exception { + return this.heartBeat(ctx, brokerAddr, heartbeatData, DEFAULT_MQ_CLIENT_TIMEOUT); } - public CompletableFuture heartBeat(String brokerAddr, HeartbeatData heartbeatData, long timeout) throws Exception { + public CompletableFuture heartBeat(Context ctx, String brokerAddr, HeartbeatData heartbeatData, long timeout) throws Exception { return this.getClient().sendHeartbeatAsync(brokerAddr, heartbeatData, timeout); } - public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader) throws Exception { - this.endTransaction(brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + public void endTransaction(Context ctx, String brokerAddr, EndTransactionRequestHeader requestHeader) throws Exception { + this.endTransaction(ctx, brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } - public void endTransaction(String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { + public void endTransaction(Context ctx, String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { this.getClient().endTransactionOneway(brokerAddr, requestHeader, "end transaction from rmq proxy", timeoutMillis); } public CompletableFuture sendMessage( + Context ctx, String address, String brokerName, List msg, SendMessageRequestHeader requestHeader ) { - return this.sendMessage(address, brokerName, msg, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.sendMessage(ctx, address, brokerName, msg, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture sendMessage( + Context ctx, String address, String brokerName, List msg, @@ -91,10 +94,11 @@ public class ForwardProducer extends AbstractForwardClient { } else { future = this.getClient().sendMessageAsync(address, brokerName, msg, requestHeader, timeoutMillis); } - return processSendMessageResponseFuture(address, requestHeader, future); + return processSendMessageResponseFuture(ctx, address, requestHeader, future); } - private CompletableFuture processSendMessageResponseFuture( + protected CompletableFuture processSendMessageResponseFuture( + Context ctx, String address, SendMessageRequestHeader requestHeader, CompletableFuture future) { @@ -108,14 +112,14 @@ public class ForwardProducer extends AbstractForwardClient { }); } - public CompletableFuture sendMessageBackThenAckOrg(String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, + public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, AckMessageRequestHeader ackMessageRequestHeader) { - return sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader,DEFAULT_MQ_CLIENT_TIMEOUT); + return sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader,DEFAULT_MQ_CLIENT_TIMEOUT); } - public CompletableFuture sendMessageBackThenAckOrg(String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, + public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, AckMessageRequestHeader ackMessageRequestHeader, long timeoutMillis) { - return this.sendMessageBack(brokerAddr, sendMsgBackRequestHeader, timeoutMillis).whenComplete((result, throwable) -> { + return this.sendMessageBack(ctx, brokerAddr, sendMsgBackRequestHeader, timeoutMillis).whenComplete((result, throwable) -> { if (throwable != null || ResponseCode.SUCCESS != result.getCode()) { return; } @@ -123,11 +127,11 @@ public class ForwardProducer extends AbstractForwardClient { }); } - public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { - return this.sendMessageBack(brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + public CompletableFuture sendMessageBack(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { + return this.sendMessageBack(ctx, brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } - public CompletableFuture sendMessageBack(String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture sendMessageBack(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { return this.getClient().sendMessageBackAsync(brokerAddr, requestHeader, timeoutMillis); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java index e45db1cbf3..13973e8882 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector; +import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PullResult; @@ -46,12 +47,13 @@ public class ForwardReadConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - public CompletableFuture popMessage(String address, String brokerName, + public CompletableFuture popMessage(Context ctx, String address, String brokerName, PopMessageRequestHeader requestHeader) { - return this.popMessage(address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.popMessage(ctx, address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture popMessage( + Context ctx, String address, String brokerName, PopMessageRequestHeader requestHeader, @@ -60,11 +62,11 @@ public class ForwardReadConsumer extends AbstractForwardClient { return this.getClient().popMessageAsync(address, brokerName, requestHeader, timeoutMillis); } - public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader) { - return this.pullMessage(address, requestHeader, MAX_CONSUMER_TIMEOUT_MILLIS); + public CompletableFuture pullMessage(Context ctx, String address, PullMessageRequestHeader requestHeader) { + return this.pullMessage(ctx, address, requestHeader, MAX_CONSUMER_TIMEOUT_MILLIS); } - public CompletableFuture pullMessage(String address, PullMessageRequestHeader requestHeader, + public CompletableFuture pullMessage(Context ctx, String address, PullMessageRequestHeader requestHeader, long timeoutMillis) { return this.getClient().pullMessageAsync(address, requestHeader, timeoutMillis); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 60332c063b..6be934cbb6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.connector; +import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; @@ -47,11 +48,12 @@ public class ForwardWriteConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - public CompletableFuture ackMessage(String address, AckMessageRequestHeader requestHeader) { - return this.ackMessage(address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + public CompletableFuture ackMessage(Context ctx, String address, AckMessageRequestHeader requestHeader) { + return this.ackMessage(ctx, address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture ackMessage( + Context ctx, String address, AckMessageRequestHeader requestHeader, long timeoutMillis @@ -60,14 +62,16 @@ public class ForwardWriteConsumer extends AbstractForwardClient { } public CompletableFuture changeInvisibleTimeAsync( + Context ctx, String address, String brokerName, ChangeInvisibleTimeRequestHeader requestHeader ) { - return this.changeInvisibleTimeAsync(address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.changeInvisibleTimeAsync(ctx, address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture changeInvisibleTimeAsync( + Context ctx, String address, String brokerName, ChangeInvisibleTimeRequestHeader requestHeader, @@ -77,6 +81,7 @@ public class ForwardWriteConsumer extends AbstractForwardClient { } public void updateConsumerOffsetOneWay( + Context ctx, String brokerAddr, UpdateConsumerOffsetRequestHeader header, long timeoutMillis diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java index 830bd29b69..92c7d63964 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.connector.transaction; import com.google.common.collect.Sets; +import io.grpc.Context; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -174,6 +175,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData) { try { + Context ctx = Context.current(); MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(clusterName); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); if (brokerDataList == null) { @@ -183,7 +185,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { heartbeatExecutors.submit(() -> { String brokerAddr = brokerData.selectBrokerAddr(); try { - this.forwardProducer.heartBeat(brokerAddr, heartbeatData); + this.forwardProducer.heartBeat(ctx, brokerAddr, heartbeatData); } catch (Exception e) { log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, e); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 3c9ac57364..dcbbf600c4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -102,6 +102,7 @@ public class ConsumerService extends BaseService { } future = this.readConsumer.popMessage( + ctx, messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), requestHeader, @@ -210,7 +211,7 @@ public class ConsumerService extends BaseService { group, handle); - future = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); + future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); } catch (Throwable t) { future.completeExceptionally(t); } @@ -238,7 +239,7 @@ public class ConsumerService extends BaseService { ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); ackMessageRequestHeader.setOffset(handle.getOffset()); - future = this.writeConsumer.ackMessage(brokerAddr, ackMessageRequestHeader); + future = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageRequestHeader); } catch (Throwable t) { future.completeExceptionally(t); } @@ -297,7 +298,7 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); - CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(brokerAddr, requestHeader); + CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, requestHeader); ackResultFuture .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) .exceptionally(throwable -> { @@ -341,11 +342,13 @@ public class ConsumerService extends BaseService { int maxDeliveryAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { future = this.producer.sendMessageBack( + ctx, brokerAddr, this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts) ).thenApply(result -> { if (result.getCode() == ResponseCode.SUCCESS) { writeConsumer.ackMessage( + ctx, brokerAddr, this.buildAckMessageRequestHeader(ctx, request)); } @@ -353,7 +356,7 @@ public class ConsumerService extends BaseService { }); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader) + future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), requestHeader) .thenApply(result -> convertToNackMessageResponse(ctx, request, result)); } } catch (Throwable t) { @@ -411,7 +414,7 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(brokerAddr, receiptHandle.getBrokerName(), requestHeader) + future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), requestHeader) .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index d3f0e1c812..38fb8adec8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -67,6 +67,7 @@ public class ProducerService extends BaseService { // send message to broker. future = this.producer.sendMessage( + ctx, selectableMessageQueue.getBrokerAddr(), selectableMessageQueue.getBrokerName(), convertToMessageList(ctx, request), @@ -128,7 +129,7 @@ public class ProducerService extends BaseService { AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( request.getTopic(), request.getGroup(), receiptHandle); - future = this.producer.sendMessageBackThenAckOrg(brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) + future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) .thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index eea4722e0a..eb71fa848e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -99,7 +99,7 @@ public class TransactionService extends BaseService implements TransactionStateC TransactionId handle = TransactionId.decode(request.getTransactionId()); String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); - this.forwardProducer.endTransaction(brokerAddr, requestHeader); + this.forwardProducer.endTransaction(ctx, brokerAddr, requestHeader); future.complete(EndTransactionResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 5d993ee4f0..ee57c45e7e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -76,10 +76,10 @@ public class ConsumerServiceTest extends BaseServiceTest { createMessageExt("msg2", "msg2") ); PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); - when(readConsumerClient.popMessage(anyString(), anyString(), any(), anyLong())) + when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - when(writeConsumerClient.ackMessage(anyString(), any())) + when(writeConsumerClient.ackMessage(any(), anyString(), any())) .thenReturn(CompletableFuture.completedFuture(new AckResult())); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); @@ -127,15 +127,15 @@ public class ConsumerServiceTest extends BaseServiceTest { createMessageExt("msg2", "msg2") ); PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); - when(readConsumerClient.popMessage(anyString(), anyString(), any(), anyLong())) + when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); List toDLQMsgId = new ArrayList<>(); doAnswer(mock -> { - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = mock.getArgument(1); + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = mock.getArgument(2); toDLQMsgId.add(sendMsgBackRequestHeader.getOriginMsgId()); return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBackThenAckOrg(anyString(), any(), any()); + }).when(producerClient).sendMessageBackThenAckOrg(any(), anyString(), any(), any()); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); List responseList = consumerService.receiveMessage(ctx, @@ -164,7 +164,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.ackMessage(anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); + when(writeConsumerClient.ackMessage(any(), anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); AckMessageResponse response = consumerService.ackMessage(Context.current(), AckMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -187,9 +187,9 @@ public class ConsumerServiceTest extends BaseServiceTest { ReceiptHandle receiptHandle = createReceiptHandle(); AtomicReference headerRef = new AtomicReference<>(); doAnswer(mock -> { - headerRef.set(mock.getArgument(1)); + headerRef.set(mock.getArgument(2)); return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBack(anyString(), any()); + }).when(producerClient).sendMessageBack(any(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); @@ -216,11 +216,11 @@ public class ConsumerServiceTest extends BaseServiceTest { ReceiptHandle receiptHandle = createReceiptHandle(); AtomicReference headerRef = new AtomicReference<>(); doAnswer(mock -> { - headerRef.set(mock.getArgument(2)); + headerRef.set(mock.getArgument(3)); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); return CompletableFuture.completedFuture(ackResult); - }).when(writeConsumerClient).changeInvisibleTimeAsync(anyString(), anyString(), any()); + }).when(writeConsumerClient).changeInvisibleTimeAsync(any(), anyString(), anyString(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 566f0c763b..e350682276 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -66,7 +66,7 @@ public class ProducerServiceTest extends BaseServiceTest { @Test public void testSendMessage() { CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any())) + when(producerClient.sendMessage(any(), anyString(), anyString(), any(), any())) .thenReturn(sendResultFuture); sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), 1L, "txId", "offsetMsgId", "regionId")); @@ -121,7 +121,7 @@ public class ProducerServiceTest extends BaseServiceTest { RuntimeException ex = new RuntimeException(); CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(anyString(), anyString(), any(), any())) + when(producerClient.sendMessage(any(), anyString(), anyString(), any(), any())) .thenReturn(sendResultFuture); sendResultFuture.completeExceptionally(ex); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index 5909ffac16..e9344d62c7 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -72,10 +72,10 @@ public class TransactionServiceTest extends BaseServiceTest { RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "71F99B78B6E261357FA259CCA6456118", 1234, 5678); doAnswer(mock -> { - brokerAddrRef.set(mock.getArgument(0)); - headerRef.set(mock.getArgument(1)); + brokerAddrRef.set(mock.getArgument(1)); + headerRef.set(mock.getArgument(2)); return null; - }).when(producerClient).endTransaction(anyString(), any()); + }).when(producerClient).endTransaction(any(), anyString(), any()); EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() .setTransactionId(transactionId.getProxyTransactionId()) From 862e77aefc72afd9bac7309595c3395e82631427 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 16:04:08 +0800 Subject: [PATCH 130/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/GrpcMessagingProcessor.java | 10 +--------- .../grpc/v2/service/ClusterGrpcService.java | 7 +++---- .../grpc/v2/service/GrpcForwardService.java | 3 +-- .../v2/service/cluster/ConsumerService.java | 17 ++++++++++++++++- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index 6317cddae3..586061b3e4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -117,15 +117,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - CompletableFuture> future = grpcForwardService.receiveMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReceiveMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + grpcForwardService.receiveMessage(Context.current(), request, responseObserver); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 7dfd982981..9c4d663d67 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -42,8 +42,6 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; -import java.util.Iterator; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -123,8 +121,9 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc } @Override - public CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { - return consumerService.receiveMessage(ctx, request).thenApply(List::iterator); + public void receiveMessage(Context ctx, ReceiveMessageRequest request, + StreamObserver responseObserver) { + consumerService.receiveMessage(ctx, request, responseObserver); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java index b1c984defe..48d2f2504f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java @@ -42,7 +42,6 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; -import java.util.Iterator; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -56,7 +55,7 @@ public interface GrpcForwardService extends StartAndShutdown { CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request); + void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver); CompletableFuture nackMessage(Context ctx, NackMessageRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index dcbbf600c4..fb8a277353 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -33,6 +33,7 @@ import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import io.grpc.Context; +import io.grpc.stub.StreamObserver; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -59,6 +60,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -90,7 +92,20 @@ public class ConsumerService extends BaseService { this.grpcClientManager = grpcClientManager; } - public CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { + public void receiveMessage(Context ctx, ReceiveMessageRequest request, + StreamObserver responseObserver) { + this.receiveMessage(ctx, request) + .thenAccept(responses -> ResponseWriter.write(responseObserver, responses.iterator())) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(e)).build() + ); + return null; + }); + } + + protected CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { CompletableFuture> future = new CompletableFuture<>(); try { From 7ce66f1793fbc4250bc2c6bdce6b232a3bb15154 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 17:10:54 +0800 Subject: [PATCH 131/338] [ISSUE #3949] v2 support --- .../grpc/v2/service/ClusterGrpcService.java | 7 +- .../grpc/v2/service/cluster/BaseService.java | 24 ++- .../v2/service/cluster/ConsumerService.java | 163 +++-------------- .../DefaultReceiveMessageResultFilter.java | 173 ++++++++++++++++++ .../service/cluster/ForwardClientService.java | 4 +- .../v2/service/cluster/ProducerService.java | 8 +- .../cluster/ReceiveMessageResultFilter.java | 29 +++ .../grpc/v2/service/cluster/RouteService.java | 168 +++++------------ .../service/cluster/ConsumerServiceTest.java | 9 +- .../cluster/ForwardClientServiceTest.java | 1 + .../service/cluster/ProducerServiceTest.java | 9 +- .../v2/service/cluster/RouteServiceTest.java | 57 +----- 12 files changed, 324 insertions(+), 328 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 9c4d663d67..bea689d077 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -91,13 +91,18 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); this.consumerService = new ConsumerService(connectorManager, grpcClientManager); this.producerService = new ProducerService(connectorManager); - this.routeService = new RouteService(ProxyMode.CLUSTER, connectorManager, grpcClientManager); + this.routeService = new RouteService(connectorManager, grpcClientManager); this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, channelManager, grpcClientManager, pollCommandResponseManager); this.transactionService = new TransactionService(connectorManager, channelManager); this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); this.appendStartAndShutdown(this.connectorManager); + this.appendStartAndShutdown(this.consumerService); + this.appendStartAndShutdown(this.producerService); + this.appendStartAndShutdown(this.routeService); + this.appendStartAndShutdown(this.clientService); + this.appendStartAndShutdown(this.transactionService); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java index 835e31f6b8..9843cf7d3a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java @@ -22,11 +22,13 @@ import apache.rocketmq.v2.Resource; import io.grpc.Context; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -public class BaseService { +public abstract class BaseService implements StartAndShutdown { protected final ConnectorManager connectorManager; @@ -34,7 +36,7 @@ public class BaseService { this.connectorManager = connectorManager; } - protected ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { + public static ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); if (receiptHandle.isExpired()) { throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); @@ -42,20 +44,34 @@ public class BaseService { return receiptHandle; } - protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { + public static String getBrokerAddr(Context ctx, TopicRouteCache topicRouteCache, String brokerName) throws Exception { if (StringUtils.isBlank(brokerName)) { throw new ProxyException(Code.UNRECOGNIZED, "broker name is empty"); } - String addr = this.connectorManager.getTopicRouteCache().getBrokerAddr(brokerName); + String addr = topicRouteCache.getBrokerAddr(brokerName); if (StringUtils.isBlank(addr)) { throw new ProxyException(Code.UNRECOGNIZED, brokerName + " not exist"); } return addr; } + protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { + return getBrokerAddr(ctx, this.connectorManager.getTopicRouteCache(), brokerName); + } + protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { // for checking filterExpression. String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcConverter.buildSubscriptionData(topicName, filterExpression); } + + @Override + public void start() throws Exception { + + } + + @Override + public void shutdown() throws Exception { + + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index fb8a277353..56a917ad68 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -22,20 +22,17 @@ import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; @@ -43,14 +40,10 @@ import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; @@ -74,9 +67,8 @@ public class ConsumerService extends BaseService { protected final GrpcClientManager grpcClientManager; private volatile ReadQueueSelector readQueueSelector; + private volatile ReceiveMessageResultFilter receiveMessageResultFilter; private volatile ResponseHook> receiveMessageHook; - private volatile ResponseHook ackNoMatchedMessageHook; - private volatile ResponseHook forwardToDLQInRecvMessageHook; private volatile ResponseHook ackMessageHook; private volatile ResponseHook nackMessageHook; private volatile ResponseHook changeInvisibleDurationHook; @@ -86,12 +78,16 @@ public class ConsumerService extends BaseService { this.readConsumer = connectorManager.getForwardReadConsumer(); this.writeConsumer = connectorManager.getForwardWriteConsumer(); this.producer = connectorManager.getForwardProducer(); - - this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); - this.grpcClientManager = grpcClientManager; } + @Override + public void start() throws Exception { + this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); + this.receiveMessageResultFilter = new DefaultReceiveMessageResultFilter( + producer, writeConsumer, grpcClientManager, connectorManager.getTopicRouteCache()); + } + public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { this.receiveMessage(ctx, request) @@ -146,10 +142,10 @@ public class ConsumerService extends BaseService { PopStatus status = result.getPopStatus(); switch (status) { case FOUND: - List messageList = filterMessage(ctx, request, result.getMsgFoundList()); + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); if (messageList.isEmpty()) { responseList.add(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) .build()); } else { for (Message message : messageList) { @@ -176,97 +172,6 @@ public class ConsumerService extends BaseService { return responseList; } - protected List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { - if (messageExtList == null || messageExtList.isEmpty()) { - return Collections.emptyList(); - } - Settings settings = grpcClientManager.getClientSettings(ctx); - ClientType clientType = settings.getClientType(); - int maxAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); - Resource topic = request.getMessageQueue().getTopic(); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); - - List resMessageList = new ArrayList<>(); - for (MessageExt messageExt : messageExtList) { - if (ClientType.SIMPLE_CONSUMER.equals(clientType) && messageExt.getReconsumeTimes() >= maxAttempts) { - forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); - continue; - } - if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { - this.ackNoMatchedMessage(ctx, request, messageExt); - continue; - } - resMessageList.add(GrpcConverter.buildMessage(messageExt)); - } - return resMessageList; - } - - protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, - int maxReconsumeTimes) { - CompletableFuture future = new CompletableFuture<>(); - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - - try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); - Resource topic = request.getMessageQueue().getTopic(); - Resource group = request.getGroup(); - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( - topic, - group, - handle, - messageExt.getMsgId(), - maxReconsumeTimes); - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( - topic, - group, - handle); - - future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((result, throwable) -> { - if (forwardToDLQInRecvMessageHook != null) { - forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); - } - }); - } - - protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { - CompletableFuture future = new CompletableFuture<>(); - - AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); - try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - String brokerAddr = this.getBrokerAddr(ctx, handle.getBrokerName()); - ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); - ackMessageRequestHeader.setTopic(messageExt.getTopic()); - ackMessageRequestHeader.setQueueId(handle.getQueueId()); - ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); - ackMessageRequestHeader.setOffset(handle.getOffset()); - - future = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageRequestHeader); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((ackResult, throwable) -> { - if (ackNoMatchedMessageHook != null) { - ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); - } - }); - - } - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -309,7 +214,7 @@ public class ConsumerService extends BaseService { .setReceiptHandle(ackMessageEntry.getReceiptHandle()); try { - ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); + ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); @@ -350,25 +255,18 @@ public class ConsumerService extends BaseService { public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); Settings settings = grpcClientManager.getClientSettings(ctx); int maxDeliveryAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { - future = this.producer.sendMessageBack( + future = this.producer.sendMessageBackThenAckOrg( ctx, brokerAddr, - this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts) - ).thenApply(result -> { - if (result.getCode() == ResponseCode.SUCCESS) { - writeConsumer.ackMessage( - ctx, - brokerAddr, - this.buildAckMessageRequestHeader(ctx, request)); - } - return convertToNackMessageResponse(ctx, request, result); - }); + this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts), + this.buildAckMessageRequestHeader(ctx, request) + ).thenApply(result -> convertToNackMessageResponse(ctx, request, result)); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), requestHeader) @@ -425,7 +323,7 @@ public class ConsumerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); try { - ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); @@ -468,6 +366,15 @@ public class ConsumerService extends BaseService { this.readQueueSelector = readQueueSelector; } + public ReceiveMessageResultFilter getReceiveMessageResultFilter() { + return receiveMessageResultFilter; + } + + public void setReceiveMessageResultFilter( + ReceiveMessageResultFilter receiveMessageResultFilter) { + this.receiveMessageResultFilter = receiveMessageResultFilter; + } + public ResponseHook> getReceiveMessageHook() { return receiveMessageHook; } @@ -477,24 +384,6 @@ public class ConsumerService extends BaseService { this.receiveMessageHook = receiveMessageHook; } - public ResponseHook getAckNoMatchedMessageHook() { - return ackNoMatchedMessageHook; - } - - public void setAckNoMatchedMessageHook( - ResponseHook ackNoMatchedMessageHook) { - this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; - } - - public ResponseHook getForwardToDLQInRecvMessageHook() { - return forwardToDLQInRecvMessageHook; - } - - public void setForwardToDLQInRecvMessageHook( - ResponseHook forwardToDLQInRecvMessageHook) { - this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; - } - public ResponseHook getAckMessageHook() { return ackMessageHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java new file mode 100644 index 0000000000..15b5b35c69 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -0,0 +1,173 @@ +/* + * 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.grpc.v2.service.cluster; + +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; +import org.apache.rocketmq.proxy.connector.ForwardProducer; +import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +import static org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseService.getBrokerAddr; + +public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFilter { + + protected final ForwardProducer producer; + protected final ForwardWriteConsumer writeConsumer; + protected final GrpcClientManager grpcClientManager; + protected final TopicRouteCache topicRouteCache; + + private volatile ResponseHook ackNoMatchedMessageHook; + private volatile ResponseHook forwardToDLQInRecvMessageHook; + + public DefaultReceiveMessageResultFilter(ForwardProducer producer, ForwardWriteConsumer writeConsumer, + GrpcClientManager grpcClientManager, TopicRouteCache topicRouteCache) { + this.producer = producer; + this.writeConsumer = writeConsumer; + this.grpcClientManager = grpcClientManager; + this.topicRouteCache = topicRouteCache; + } + + @Override + public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { + if (messageExtList == null || messageExtList.isEmpty()) { + return Collections.emptyList(); + } + Settings settings = grpcClientManager.getClientSettings(ctx); + ClientType clientType = settings.getClientType(); + int maxAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); + Resource topic = request.getMessageQueue().getTopic(); + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); + + List resMessageList = new ArrayList<>(); + for (MessageExt messageExt : messageExtList) { + if (ClientType.SIMPLE_CONSUMER.equals(clientType) && messageExt.getReconsumeTimes() >= maxAttempts) { + forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); + continue; + } + if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + this.ackNoMatchedMessage(ctx, request, messageExt); + continue; + } + resMessageList.add(GrpcConverter.buildMessage(messageExt)); + } + return resMessageList; + } + + protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, + int maxReconsumeTimes) { + CompletableFuture future = new CompletableFuture<>(); + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); + Resource topic = request.getMessageQueue().getTopic(); + Resource group = request.getGroup(); + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( + topic, + group, + handle, + messageExt.getMsgId(), + maxReconsumeTimes); + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( + topic, + group, + handle); + + future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); + } catch (Throwable t) { + future.completeExceptionally(t); + } + + future.whenComplete((result, throwable) -> { + if (forwardToDLQInRecvMessageHook != null) { + forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); + } + }); + } + + protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { + CompletableFuture future = new CompletableFuture<>(); + + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); + ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); + ackMessageRequestHeader.setTopic(messageExt.getTopic()); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + + future = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageRequestHeader); + } catch (Throwable t) { + future.completeExceptionally(t); + } + + future.whenComplete((ackResult, throwable) -> { + if (ackNoMatchedMessageHook != null) { + ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); + } + }); + } + + public ResponseHook getAckNoMatchedMessageHook() { + return ackNoMatchedMessageHook; + } + + public void setAckNoMatchedMessageHook( + ResponseHook ackNoMatchedMessageHook) { + this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; + } + + public ResponseHook getForwardToDLQInRecvMessageHook() { + return forwardToDLQInRecvMessageHook; + } + + public void setForwardToDLQInRecvMessageHook( + ResponseHook forwardToDLQInRecvMessageHook) { + this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 45b1d40705..0c7fde9b43 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -82,9 +82,11 @@ public class ForwardClientService extends BaseService { this.channelManager = channelManager; this.grpcClientManager = grpcClientManager; this.telemetryCommandManager = telemetryCommandManager; + } + @Override + public void start() throws Exception { this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); - this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); this.producerManager = new ProducerManager(); this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 38fb8adec8..8bb0b3909e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -53,7 +53,11 @@ public class ProducerService extends BaseService { public ProducerService(ConnectorManager connectorManager) { super(connectorManager); this.producer = connectorManager.getForwardProducer(); - writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); + } + + @Override + public void start() throws Exception { + this.writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); } public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { @@ -123,7 +127,7 @@ public class ProducerService extends BaseService { CompletableFuture future = new CompletableFuture<>(); try { - ReceiptHandle receiptHandle = this.resolveReceiptHandle(ctx, request.getReceiptHandle()); + ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java new file mode 100644 index 0000000000..cd291b493b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; + +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import io.grpc.Context; +import java.util.List; +import org.apache.rocketmq.common.message.MessageExt; + +public interface ReceiveMessageResultFilter { + + List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index aba9cef649..d91bcb4ccc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -16,8 +16,6 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.Assignment; import apache.rocketmq.v2.Broker; import apache.rocketmq.v2.Code; @@ -29,32 +27,23 @@ import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.Settings; -import com.google.common.base.Preconditions; -import com.google.common.net.HostAndPort; import io.grpc.Context; 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.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.ParameterConverter; -import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; public class RouteService extends BaseService { - private final ProxyMode mode; - private volatile ParameterConverter queryRouteEndpointConverter; private volatile ResponseHook queryRouteHook; @@ -64,14 +53,16 @@ public class RouteService extends BaseService { protected final GrpcClientManager grpcClientManager; - public RouteService(ProxyMode mode, ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { + public RouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { super(connectorManager); - Preconditions.checkArgument(ProxyMode.isClusterMode(mode) || ProxyMode.isLocalMode(mode)); - this.mode = mode; + this.grpcClientManager = grpcClientManager; + } + + @Override + public void start() throws Exception { this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); - this.grpcClientManager = grpcClientManager; } public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { @@ -87,44 +78,26 @@ public class RouteService extends BaseService { MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); List queueDataList = topicRouteData.getQueueDatas(); - List brokerDataList = topicRouteData.getBrokerDatas(); List messageQueueList = new ArrayList<>(); - if (ProxyMode.isClusterMode(mode.name())) { - Settings clientSettings = grpcClientManager.getClientSettings(ctx); - Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); - if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { - future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - clientSettings.getAccessPoint() + " is invalidate")) - .build()); - return future; - } - for (QueueData queueData : queueDataList) { - Broker broker = Broker.newBuilder() - .setName(queueData.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); - - messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); - } + Settings clientSettings = grpcClientManager.getClientSettings(ctx); + Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); + if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { + future.complete(QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + + clientSettings.getAccessPoint() + " is invalidate")) + .build()); + return future; } - if (ProxyMode.isLocalMode(mode.name())) { - Map> brokerMap = buildBrokerMap(brokerDataList); + for (QueueData queueData : queueDataList) { + Broker broker = Broker.newBuilder() + .setName(queueData.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); - for (QueueData queueData : queueDataList) { - String brokerName = queueData.getBrokerName(); - Map brokerIdMap = brokerMap.get(brokerName); - if (brokerIdMap == null) { - break; - } - for (Broker broker : brokerIdMap.values()) { - messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); - } - } + messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); } - QueryRouteResponse response = QueryRouteResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .addAllMessageQueues(messageQueueList) @@ -153,57 +126,32 @@ public class RouteService extends BaseService { try { List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); - if (ProxyMode.isLocalMode(mode)) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); - TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); - Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); - for (SelectableMessageQueue messageQueue : messageQueueList) { - Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); - if (brokerIdMap != null) { - Broker broker = brokerIdMap.get(0L); - - MessageQueue defaultMessageQueue = MessageQueue.newBuilder() - .setTopic(request.getTopic()) - .setId(-1) - .setPermission(Permission.READ_WRITE) - .setBroker(broker) - .build(); - - assignments.add(Assignment.newBuilder() - .setMessageQueue(defaultMessageQueue) - .build()); - } - } + Settings clientSettings = grpcClientManager.getClientSettings(ctx); + Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); + if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { + future.complete(QueryAssignmentResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + + clientSettings.getAccessPoint() + " is invalidate")) + .build()); + return future; } - if (ProxyMode.isClusterMode(mode)) { - Settings clientSettings = grpcClientManager.getClientSettings(ctx); - Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); - if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { - future.complete(QueryAssignmentResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - clientSettings.getAccessPoint() + " is invalidate")) - .build()); - return future; - } - for (SelectableMessageQueue messageQueue : messageQueueList) { - Broker broker = Broker.newBuilder() - .setName(messageQueue.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); + for (SelectableMessageQueue messageQueue : messageQueueList) { + Broker broker = Broker.newBuilder() + .setName(messageQueue.getBrokerName()) + .setId(0) + .setEndpoints(resEndpoints) + .build(); - MessageQueue defaultMessageQueue = MessageQueue.newBuilder() - .setTopic(request.getTopic()) - .setId(-1) - .setPermission(Permission.READ_WRITE) - .setBroker(broker) - .build(); + MessageQueue defaultMessageQueue = MessageQueue.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(Permission.READ_WRITE) + .setBroker(broker) + .build(); - assignments.add(Assignment.newBuilder() - .setMessageQueue(defaultMessageQueue) - .build()); - } + assignments.add(Assignment.newBuilder() + .setMessageQueue(defaultMessageQueue) + .build()); } QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() @@ -217,34 +165,6 @@ public class RouteService extends BaseService { return future; } - private Map> buildBrokerMap(List brokerDataList) { - Map> brokerMap = new HashMap<>(); - for (BrokerData brokerData : brokerDataList) { - Map brokerIdMap = new HashMap<>(); - String brokerName = brokerData.getBrokerName(); - for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { - Long brokerId = entry.getKey(); - HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); - Broker broker = Broker.newBuilder() - .setName(brokerName) - .setId(Math.toIntExact(brokerId)) - .setEndpoints(Endpoints.newBuilder() - .setScheme(AddressScheme.IPv4) - .addAddresses( - Address.newBuilder() - .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) - .setHost(hostAndPort.getHost()) - ) - .build()) - .build(); - - brokerIdMap.put(brokerId, broker); - } - brokerMap.put(brokerName, brokerIdMap); - } - return brokerMap; - } - public ParameterConverter getQueryRouteEndpointConverter() { return queryRouteEndpointConverter; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index ee57c45e7e..353c743bc1 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -51,10 +51,15 @@ public class ConsumerServiceTest extends BaseServiceTest { private ReadQueueSelector readQueueSelector; private ConsumerService consumerService; + private DefaultReceiveMessageResultFilter receiveMessageResultFilter; @Override public void beforeEach() throws Throwable { consumerService = new ConsumerService(this.connectorManager, this.grpcClientManager); + consumerService.start(); + + receiveMessageResultFilter = new DefaultReceiveMessageResultFilter(producerClient, writeConsumerClient, grpcClientManager, topicRouteCache); + consumerService.setReceiveMessageResultFilter(receiveMessageResultFilter); consumerService.setReadQueueSelector(readQueueSelector); } @@ -84,7 +89,7 @@ public class ConsumerServiceTest extends BaseServiceTest { Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); AtomicReference ackHandler = new AtomicReference<>(); - consumerService.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); + receiveMessageResultFilter.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); List responseList = consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() @@ -189,7 +194,7 @@ public class ConsumerServiceTest extends BaseServiceTest { doAnswer(mock -> { headerRef.set(mock.getArgument(2)); return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBack(any(), anyString(), any()); + }).when(producerClient).sendMessageBackThenAckOrg(any(), anyString(), any(), any()); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index 8ea04fe051..ad1bb98c0e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -47,6 +47,7 @@ public class ForwardClientServiceTest extends BaseServiceTest { this.channelManager, this.grpcClientManager, this.telemetryCommandManager); + clientService.start(); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index e350682276..fee74d2176 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -46,6 +46,8 @@ import static org.mockito.Mockito.when; public class ProducerServiceTest extends BaseServiceTest { + private ProducerService producerService; + private static final SendMessageRequest REQUEST = SendMessageRequest.newBuilder() .addMessages(Message.newBuilder() .setTopic(Resource.newBuilder() @@ -61,6 +63,8 @@ public class ProducerServiceTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { + producerService = new ProducerService(this.connectorManager); + producerService.start(); } @Test @@ -71,7 +75,6 @@ public class ProducerServiceTest extends BaseServiceTest { sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), 1L, "txId", "offsetMsgId", "regionId")); - ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); @@ -88,8 +91,6 @@ public class ProducerServiceTest extends BaseServiceTest { @Test public void testSendMessageNoQueueSelect() { - ProducerService producerService = new ProducerService(this.connectorManager); - producerService.setWriteQueueSelector((ctx, request) -> null); CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() @@ -125,7 +126,6 @@ public class ProducerServiceTest extends BaseServiceTest { .thenReturn(sendResultFuture); sendResultFuture.completeExceptionally(ex); - ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request) -> new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); @@ -145,7 +145,6 @@ public class ProducerServiceTest extends BaseServiceTest { public void testSendMessageWithErrorThrow() { RuntimeException ex = new RuntimeException(); - ProducerService producerService = new ProducerService(this.connectorManager); producerService.setWriteQueueSelector((ctx, request) -> { throw ex; }); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index e4e5e6fe4c..b013eb5965 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -30,7 +30,6 @@ import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; -import com.google.common.net.HostAndPort; import io.grpc.Context; import java.util.ArrayList; import java.util.HashMap; @@ -44,7 +43,6 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -77,6 +75,8 @@ public class RouteServiceTest extends BaseServiceTest { .setAccessPoint(Endpoints.getDefaultInstance()) .build(); + private RouteService routeService; + @Override public void beforeEach() throws Exception { TopicRouteData routeData = new TopicRouteData(); @@ -106,6 +106,9 @@ public class RouteServiceTest extends BaseServiceTest { when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + + routeService = new RouteService(this.connectorManager, this.grpcClientManager); + routeService.start(); } @Test @@ -161,28 +164,8 @@ public class RouteServiceTest extends BaseServiceTest { return queueData; } - @Test - public void testLocalModeQueryRoute() throws Exception { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); - - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .build()); - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(8, response.getMessageQueuesCount()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getMessageQueues(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } - @Test public void testQueryRouteWithInvalidEndpoints() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -196,8 +179,6 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryRoute() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() @@ -215,8 +196,6 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryRouteWhenTopicNotExist() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() @@ -231,8 +210,6 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testQueryAssignmentInvalidEndpoints() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() .setTopic( @@ -246,32 +223,8 @@ public class RouteServiceTest extends BaseServiceTest { assertEquals(Code.ILLEGAL_ACCESS_POINT.getNumber(), response.getStatus().getCode().getNumber()); } - @Test - public void testLocalModeQueryAssignment() throws Exception { - RouteService routeService = new RouteService(ProxyMode.LOCAL, this.connectorManager, this.grpcClientManager); - - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build()); - - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); - } - @Test public void testQueryAssignment() throws Exception { - RouteService routeService = new RouteService(ProxyMode.CLUSTER, this.connectorManager, this.grpcClientManager); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() From 21e436b8a2938c09319a07682de6fd360169fb03 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 25 Apr 2022 22:09:20 +0800 Subject: [PATCH 132/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/adapter/ResponseWriter.java | 26 ++--- .../v2/service/cluster/ConsumerService.java | 110 +++++++++--------- .../ReceiveMessageResponseStreamObserver.java | 61 ++++++++++ .../service/cluster/ConsumerServiceTest.java | 83 +++++++------ .../cluster/TransactionServiceTest.java | 31 +++-- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 76 ++++++------ 6 files changed, 226 insertions(+), 161 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 25ad9feee6..9ce43db169 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -40,38 +40,34 @@ public class ResponseWriter { } public static void writeResponse(StreamObserver observer, final T response) { + if (null == response) { + return; + } if (observer instanceof ServerCallStreamObserver) { - if (response == null) { - return; - } - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (serverCallStreamObserver.isCancelled()) { log.warn("client has cancelled the request. response to write: {}", response); return; } - - log.debug("start to write response. response: {}", response); - serverCallStreamObserver.onNext(response); } + log.debug("start to write response. response: {}", response); + observer.onNext(response); } public static void writeException(StreamObserver observer, final Throwable e) { + if (null == e) { + return; + } if (observer instanceof ServerCallStreamObserver) { - if (null == e) { - return; - } - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; if (serverCallStreamObserver.isCancelled()) { log.warn("Client has cancelled the request. Exception to write", e); return; } - - log.debug("Start to write error response", e); - serverCallStreamObserver.onError(e); - serverCallStreamObserver.onCompleted(); } + log.debug("Start to write error response", e); + observer.onError(e); + observer.onCompleted(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 56a917ad68..62b7d73597 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -68,7 +68,7 @@ public class ConsumerService extends BaseService { private volatile ReadQueueSelector readQueueSelector; private volatile ReceiveMessageResultFilter receiveMessageResultFilter; - private volatile ResponseHook> receiveMessageHook; + private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackMessageHook; private volatile ResponseHook nackMessageHook; private volatile ResponseHook changeInvisibleDurationHook; @@ -90,20 +90,11 @@ public class ConsumerService extends BaseService { public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - this.receiveMessage(ctx, request) - .thenAccept(responses -> ResponseWriter.write(responseObserver, responses.iterator())) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(e)).build() - ); - return null; - }); - } - - protected CompletableFuture> receiveMessage(Context ctx, ReceiveMessageRequest request) { - CompletableFuture> future = new CompletableFuture<>(); - + ReceiveMessageResponseStreamObserver streamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + responseObserver); try { PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); @@ -112,22 +103,17 @@ public class ConsumerService extends BaseService { throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); } - future = this.readConsumer.popMessage( + this.readConsumer.popMessage( ctx, messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), requestHeader, requestHeader.getPollTime()) - .thenApply(result -> convertToReceiveMessageResponse(ctx, request, result)); + .thenAccept(result -> writeReceiveMessageResponse(ctx, request, result, streamObserver)) + .exceptionally(e -> writeReceiveMessageResponse(ctx, e, streamObserver)); } catch (Throwable t) { - future.completeExceptionally(t); + writeReceiveMessageResponse(ctx, t, streamObserver); } - future.whenComplete((response, throwable) -> { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); - return future; } protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { @@ -136,40 +122,52 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } - protected List convertToReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, - PopResult result) { - List responseList = new ArrayList<>(); + protected void writeReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, + PopResult result, StreamObserver streamObserver) { PopStatus status = result.getPopStatus(); - switch (status) { - case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); - if (messageList.isEmpty()) { - responseList.add(ReceiveMessageResponse.newBuilder() + try { + switch (status) { + case FOUND: + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); + if (messageList.isEmpty()) { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + } else { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + for (Message message : messageList) { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setMessage(message) + .build()); + } + } + break; + case POLLING_FULL: + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .build()); + break; + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + streamObserver.onNext(ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) .build()); - } else { - for (Message message : messageList) { - responseList.add(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .setMessage(message) - .build()); - } - } - break; - case POLLING_FULL: - responseList.add(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build()); - break; - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - responseList.add(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - break; + break; + } + } finally { + streamObserver.onCompleted(); } - return responseList; + } + + protected Void writeReceiveMessageResponse(Context ctx, Throwable throwable, StreamObserver streamObserver) { + ResponseWriter.write( + streamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() + ); + return null; } public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { @@ -375,12 +373,12 @@ public class ConsumerService extends BaseService { this.receiveMessageResultFilter = receiveMessageResultFilter; } - public ResponseHook> getReceiveMessageHook() { + public ResponseHook getReceiveMessageHook() { return receiveMessageHook; } public void setReceiveMessageHook( - ResponseHook> receiveMessageHook) { + ResponseHook receiveMessageHook) { this.receiveMessageHook = receiveMessageHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java new file mode 100644 index 0000000000..d6946efb1b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; + +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; + +public class ReceiveMessageResponseStreamObserver implements StreamObserver { + + private final Context context; + private final ReceiveMessageRequest request; + private final ResponseHook receiveMessageHook; + private final StreamObserver observer; + + public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, + ResponseHook receiveMessageHook, + StreamObserver observer) { + this.context = context; + this.request = request; + this.receiveMessageHook = receiveMessageHook; + this.observer = observer; + } + + @Override + public void onNext(ReceiveMessageResponse response) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, response, null); + } + observer.onNext(response); + } + + @Override + public void onError(Throwable throwable) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, null, throwable); + } + observer.onError(throwable); + } + + @Override + public void onCompleted() { + observer.onCompleted(); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 353c743bc1..35ed62dd26 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -16,12 +16,14 @@ import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; import io.grpc.Context; -import java.util.ArrayList; +import io.grpc.stub.StreamObserver; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; @@ -36,19 +38,24 @@ import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class ConsumerServiceTest extends BaseServiceTest { @Mock private ReadQueueSelector readQueueSelector; + @Mock + private StreamObserver receiveMessageResponseStreamObserver; private ConsumerService consumerService; private DefaultReceiveMessageResultFilter receiveMessageResultFilter; @@ -90,7 +97,7 @@ public class ConsumerServiceTest extends BaseServiceTest { Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); AtomicReference ackHandler = new AtomicReference<>(); receiveMessageResultFilter.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); - List responseList = consumerService.receiveMessage(ctx, + consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setTopic(Resource.newBuilder() @@ -102,12 +109,19 @@ public class ConsumerServiceTest extends BaseServiceTest { .setType(FilterType.TAG) .setExpression("msg1") .build()) - .build() - ).get(); + .build(), + receiveMessageResponseStreamObserver + ); + ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + verify(receiveMessageResponseStreamObserver, times(2)).onNext(argument.capture()); + verify(receiveMessageResponseStreamObserver, times(1)).onCompleted(); - assertEquals(1, responseList.size()); - ReceiveMessageResponse response = responseList.get(0); + ReceiveMessageResponse response = argument.getAllValues().get(0); + assertTrue(response.hasStatus()); assertEquals(Code.OK, response.getStatus().getCode()); + + response = argument.getAllValues().get(1); + assertTrue(response.hasMessage()); assertEquals("msg1", response.getMessage().getSystemProperties().getMessageId()); assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); } @@ -135,15 +149,13 @@ public class ConsumerServiceTest extends BaseServiceTest { when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - List toDLQMsgId = new ArrayList<>(); - doAnswer(mock -> { - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = mock.getArgument(2); - toDLQMsgId.add(sendMsgBackRequestHeader.getOriginMsgId()); - return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBackThenAckOrg(any(), anyString(), any(), any()); + ArgumentCaptor sendMsgBackRequestHeaderArgumentCaptor = + ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); + when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), sendMsgBackRequestHeaderArgumentCaptor.capture(), any())) + .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); - List responseList = consumerService.receiveMessage(ctx, + consumerService.receiveMessage(ctx, ReceiveMessageRequest.newBuilder() .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() .setTopic(Resource.newBuilder() @@ -155,13 +167,20 @@ public class ConsumerServiceTest extends BaseServiceTest { .setType(FilterType.TAG) .setExpression("msg1") .build()) - .build() - ).get(); + .build(), + receiveMessageResponseStreamObserver + ); + ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + verify(receiveMessageResponseStreamObserver, times(1)).onNext(argument.capture()); + verify(receiveMessageResponseStreamObserver, times(1)).onCompleted(); - assertEquals(1, responseList.size()); - ReceiveMessageResponse response = responseList.get(0); + ReceiveMessageResponse response = argument.getValue(); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(2, toDLQMsgId.size()); + assertEquals(2, sendMsgBackRequestHeaderArgumentCaptor.getAllValues().size()); + Set toDLQMsgId = sendMsgBackRequestHeaderArgumentCaptor.getAllValues().stream() + .map(ConsumerSendMsgBackRequestHeader::getOriginMsgId).collect(Collectors.toSet()); + assertTrue(toDLQMsgId.contains("msg1")); + assertTrue(toDLQMsgId.contains("msg2")); } @Test @@ -190,11 +209,9 @@ public class ConsumerServiceTest extends BaseServiceTest { @Test public void testNackMessageToDLQ() throws Exception { ReceiptHandle receiptHandle = createReceiptHandle(); - AtomicReference headerRef = new AtomicReference<>(); - doAnswer(mock -> { - headerRef.set(mock.getArgument(2)); - return CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); - }).when(producerClient).sendMessageBackThenAckOrg(any(), anyString(), any(), any()); + ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); + when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), headerArgumentCaptor.capture(), any())) + .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); @@ -213,19 +230,17 @@ public class ConsumerServiceTest extends BaseServiceTest { .get(); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(receiptHandle.getCommitLogOffset(), headerRef.get().getOffset().longValue()); + assertEquals(receiptHandle.getCommitLogOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); } @Test public void testNackMessage() throws Exception { ReceiptHandle receiptHandle = createReceiptHandle(); - AtomicReference headerRef = new AtomicReference<>(); - doAnswer(mock -> { - headerRef.set(mock.getArgument(3)); - AckResult ackResult = new AckResult(); - ackResult.setStatus(AckStatus.OK); - return CompletableFuture.completedFuture(ackResult); - }).when(writeConsumerClient).changeInvisibleTimeAsync(any(), anyString(), anyString(), any()); + ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.OK); + when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), headerArgumentCaptor.capture())) + .thenReturn(CompletableFuture.completedFuture(ackResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); @@ -244,8 +259,8 @@ public class ConsumerServiceTest extends BaseServiceTest { .get(); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(receiptHandle.getOffset(), headerRef.get().getOffset().longValue()); - assertEquals(receiptHandle.encode(), headerRef.get().getExtraInfo()); + assertEquals(receiptHandle.getOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); + assertEquals(receiptHandle.encode(), headerArgumentCaptor.getValue().getExtraInfo()); } private Settings createClientSettings(int maxDeliveryAttempts) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index e9344d62c7..cccfe03ee4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -5,7 +5,6 @@ import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; -import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; @@ -14,13 +13,14 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.assertj.core.util.Lists; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -38,14 +38,11 @@ public class TransactionServiceTest extends BaseServiceTest { @Test public void testCheckTransactionState() { GrpcClientChannel channel = mock(GrpcClientChannel.class); - AtomicReference writeDataRef = new AtomicReference<>(); when(channelManager.getClientIdList(anyString())).thenReturn(Lists.newArrayList("clientId")); when(channelManager.getChannel(anyString(), any())).thenReturn(channel); - doAnswer(mock -> { - writeDataRef.set(mock.getArgument(0)); - return null; - }).when(channel).writeAndFlush(any()); + ArgumentCaptor flushDataCaptor = ArgumentCaptor.forClass(Object.class); + when(channel.writeAndFlush(flushDataCaptor.capture())).thenReturn(null); TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), @@ -59,23 +56,21 @@ public class TransactionServiceTest extends BaseServiceTest { createMessageExt("msgId", "msgId") )); - assertTrue(writeDataRef.get() instanceof TelemetryCommand); - TelemetryCommand response = (TelemetryCommand) writeDataRef.get(); + Object flushData = flushDataCaptor.getValue(); + assertTrue(flushData instanceof TelemetryCommand); + TelemetryCommand response = (TelemetryCommand) flushData; assertEquals(transactionId.getProxyTransactionId(), response.getRecoverOrphanedTransactionCommand().getTransactionId()); } @Test public void testEndTransaction() throws Exception { - AtomicReference headerRef = new AtomicReference<>(); - AtomicReference brokerAddrRef = new AtomicReference<>(); TransactionId transactionId = TransactionId.genByBrokerTransactionId( RemotingHelper.string2SocketAddress("127.0.0.1:8080"), "71F99B78B6E261357FA259CCA6456118", 1234, 5678); - doAnswer(mock -> { - brokerAddrRef.set(mock.getArgument(1)); - headerRef.set(mock.getArgument(2)); - return null; - }).when(producerClient).endTransaction(any(), anyString(), any()); + ArgumentCaptor brokerAddrCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor headerCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); + doNothing().when(producerClient) + .endTransaction(any(), brokerAddrCaptor.capture(), headerCaptor.capture()); EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() .setTransactionId(transactionId.getProxyTransactionId()) @@ -83,7 +78,7 @@ public class TransactionServiceTest extends BaseServiceTest { ).get(); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(transactionId.getBrokerTransactionId(), headerRef.get().getTransactionId()); - assertEquals("127.0.0.1:8080", brokerAddrRef.get()); + assertEquals(transactionId.getBrokerTransactionId(), headerCaptor.getValue().getTransactionId()); + assertEquals("127.0.0.1:8080", brokerAddrCaptor.getValue()); } } \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 0ba85b8109..41c9d84426 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -223,9 +223,8 @@ public class GrpcBaseTest extends BaseConf { this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - ReceiveMessageResponse response = receiveMessage(blockingStub, topic, group).get(0); - assertReceiveMessage(response, messageId); - String receiptHandle = response.getMessage().getSystemProperties().getReceiptHandle(); + Message responseMessage = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); + String receiptHandle = responseMessage.getSystemProperties().getReceiptHandle(); AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, messageId, receiptHandle)); assertAllAckOk(ackMessageResponse); } @@ -245,27 +244,26 @@ public class GrpcBaseTest extends BaseConf { this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); - assertReceiveMessage(receiveResponse, messageId); + Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); - Message message = receiveResponse.getMessage(); NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 1 )); assertNackMessageResponse(nackMessageResponse); - AtomicReference receiveRetryResponseRef = new AtomicReference<>(); + AtomicReference receiveRetryMessageRef = new AtomicReference<>(); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group, 1).get(0); - if (!receiveRetryResponse.hasMessage()) { + List messageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group, 1)); + if (messageList.isEmpty()) { return false; } - receiveRetryResponseRef.set(receiveRetryResponse); - return receiveRetryResponse.getMessage().getSystemProperties() + + receiveRetryMessageRef.set(messageList.get(0)); + return messageList.get(0).getSystemProperties() .getMessageId().equals(messageId); }); - message = receiveRetryResponseRef.get().getMessage(); + message = receiveRetryMessageRef.get(); nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 2 )); @@ -361,11 +359,11 @@ public class GrpcBaseTest extends BaseConf { .build()); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); - if (!receiveRetryResponse.hasMessage()) { + List retryMessageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group)); + if (retryMessageList.isEmpty()) { return false; } - return receiveRetryResponse.getMessage().getSystemProperties() + return retryMessageList.get(0).getSystemProperties() .getMessageId().equals(messageId); }); } finally { @@ -390,10 +388,9 @@ public class GrpcBaseTest extends BaseConf { this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); - ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); - assertReceiveMessage(receiveResponse, messageId); + Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); - String receiptHandle = receiveResponse.getMessage().getSystemProperties().getReceiptHandle(); + String receiptHandle = message.getSystemProperties().getReceiptHandle(); ChangeInvisibleDurationResponse changeResponse = blockingStub.changeInvisibleDuration(buildChangeInvisibleDurationRequest(topic, group, receiptHandle, 5)); assertChangeInvisibleDurationResponse(changeResponse, receiptHandle); @@ -401,13 +398,13 @@ public class GrpcBaseTest extends BaseConf { ackHandles.add(changeResponse.getReceiptHandle()); await().atMost(java.time.Duration.ofSeconds(20)).until(() -> { - ReceiveMessageResponse receiveRetryResponse = receiveMessage(blockingStub, topic, group).get(0); - if (!receiveRetryResponse.hasMessage()) { + List retryMessageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group)); + if (retryMessageList.isEmpty()) { return false; } - if (receiveRetryResponse.getMessage().getSystemProperties() + if (retryMessageList.get(0).getSystemProperties() .getMessageId().equals(messageId)) { - ackHandles.add(receiveRetryResponse.getMessage().getSystemProperties().getReceiptHandle()); + ackHandles.add(retryMessageList.get(0).getSystemProperties().getReceiptHandle()); return true; } return false; @@ -450,8 +447,7 @@ public class GrpcBaseTest extends BaseConf { AtomicInteger receiveMessageCount = new AtomicInteger(0); - ReceiveMessageResponse receiveResponse = receiveMessage(blockingStub, topic, group).get(0); - assertReceiveMessage(receiveResponse, messageId); + assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); receiveMessageCount.incrementAndGet(); DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); @@ -459,10 +455,8 @@ public class GrpcBaseTest extends BaseConf { org.apache.rocketmq.common.message.MessageQueue dlqMQ = new org.apache.rocketmq.common.message.MessageQueue(MixAll.getDLQTopic(group), broker1Name, 0); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { try { - ReceiveMessageResponse retryReceiveResponse = receiveMessage(blockingStub, topic, group, 1).get(0); - if (retryReceiveResponse.hasMessage()) { - receiveMessageCount.incrementAndGet(); - } + List messageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group, 1)); + receiveMessageCount.addAndGet(messageList.size()); PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { @@ -480,13 +474,7 @@ public class GrpcBaseTest extends BaseConf { public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { - List responseList = new ArrayList<>(); - Iterator responseIterator = stub.withDeadlineAfter(15, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(topic, group)); - while (responseIterator.hasNext()) { - responseList.add(responseIterator.next()); - } - return responseList; + return receiveMessage(stub, topic, group, 15); } public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, @@ -500,6 +488,16 @@ public class GrpcBaseTest extends BaseConf { return responseList; } + public List getMessageFromReceiveMessageResponse(List responseList) { + List messageList = new ArrayList<>(); + for (ReceiveMessageResponse response : responseList) { + if (response.hasMessage()) { + messageList.add(response.getMessage()); + } + } + return messageList; + } + public QueryRouteRequest buildQueryRouteRequest(String topic) { return QueryRouteRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -647,12 +645,14 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getReceipts(0).getMessageId()).isEqualTo(messageId); } - public void assertReceiveMessage(ReceiveMessageResponse response, String messageId) { - assertThat(response.getStatus() + public Message assertAndGetReceiveMessage(List response, String messageId) { + assertThat(response.get(0).hasStatus()).isTrue(); + assertThat(response.get(0).getStatus() .getCode()).isEqualTo(Code.OK); - assertThat(response.getMessage() + assertThat(response.get(1).getMessage() .getSystemProperties() .getMessageId()).isEqualTo(messageId); + return response.get(1).getMessage(); } public void assertAllAckOk(AckMessageResponse response) { From 9c9600d51fe6e2cc6793e2b94ee0eec758bddcf7 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 26 Apr 2022 10:55:24 +0800 Subject: [PATCH 133/338] [ISSUE #3949] v2 support * Add LocalWriteQueueSelector * Adjust for protocol * Add unit test --- .../connector/route/MessageQueueSelector.java | 4 +- .../channel/ReceiveMessageChannel.java | 3 +- .../ReceiveMessageResponseHandler.java | 26 ++--- .../grpc/v2/service/LocalGrpcService.java | 35 ++++-- .../local/LocalWriteQueueSelector.java | 101 ++++++++++++++++++ .../grpc/v2/service/LocalGrpcServiceTest.java | 56 +++++----- .../local/LocalWriteQueueSelectorTest.java | 78 ++++++++++++++ 7 files changed, 254 insertions(+), 49 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java index eff85b1472..6e40325ad7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java @@ -35,9 +35,9 @@ import org.apache.rocketmq.common.protocol.route.QueueData; public class MessageQueueSelector { private static final int BROKER_ACTING_QUEUE_ID = -1; - // multiple queues for one broker, with queueId : normal + // multiple queues for brokers with queueId : normal private final List queues = new ArrayList<>(); - // one queue for one broker, with queueId : -1 + // one queue for brokers with queueId : -1 private final List brokerActingQueues = new ArrayList<>(); private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); private final AtomicInteger queueIndex; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java index a561c1e444..8593b66023 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java @@ -19,10 +19,11 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import java.util.Iterator; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; -public class ReceiveMessageChannel extends InvocationChannel { +public class ReceiveMessageChannel extends InvocationChannel> { public ReceiveMessageChannel(ReceiveMessageResponseHandler handler) { super(handler); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index edfd795c4e..23ffb5ff6b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -21,11 +21,10 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import com.google.common.base.Stopwatch; -import com.google.protobuf.util.Durations; -import com.google.protobuf.util.Timestamps; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -44,7 +43,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; -public class ReceiveMessageResponseHandler implements ResponseHandler { +public class ReceiveMessageResponseHandler implements ResponseHandler> { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final String brokerName; private final boolean fifo; @@ -56,20 +55,16 @@ public class ReceiveMessageResponseHandler implements ResponseHandler context) { - CompletableFuture future = context.getResponse(); + InvocationContext> context) { + CompletableFuture> future = context.getResponse(); long currentTimeInMillis = System.currentTimeMillis(); long popCosts = currentTimeInMillis - context.getTimestamp(); try { Stopwatch stopWatch = Stopwatch.createStarted(); - ReceiveMessageResponse.Builder builder = ReceiveMessageResponse.newBuilder(); PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) responseCommand.readCustomHeader(); - builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); - builder.setInvisibleDuration(Durations.fromMillis(responseHeader.getInvisibleTime())) - .setDeliveryTimestamp(Timestamps.fromMillis(responseHeader.getPopTime())); + List responseList = new ArrayList<>(); - ReceiveMessageResponse response; if (responseCommand.getCode() == RemotingSysResponseCode.SUCCESS) { ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); List msgFoundList = MessageDecoder.decodes(byteBuffer); @@ -145,14 +140,19 @@ public class ReceiveMessageResponseHandler implements ResponseHandler String.valueOf(responseHeader.getPopTime())); } + responseList.add(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) + .build()); + for (MessageExt messageExt : msgFoundList) { - builder.addMessages(GrpcConverter.buildMessage(messageExt)); + ReceiveMessageResponse response = ReceiveMessageResponse.newBuilder() + .setMessage(GrpcConverter.buildMessage(messageExt)).build(); + responseList.add(response); } } - response = builder.build(); long elapsed = stopWatch.stop().elapsed(TimeUnit.MILLISECONDS); log.debug("Translating remoting response to gRPC response costs {}ms. Duration request received: {}", elapsed, popCosts); - future.complete(response); + future.complete(responseList.iterator()); } catch (Exception e) { log.error("Unexpected exception raised when handle pop remoting command", e); future.completeExceptionally(e); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index faf09fef56..920c5b2938 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -41,6 +41,7 @@ import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Settings; @@ -51,6 +52,7 @@ import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -68,6 +70,7 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; @@ -97,12 +100,14 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; @@ -120,6 +125,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final RouteService routeService; private final ClientSettingsService clientSettingsService; private final DelayPolicy delayPolicy; + private final LocalWriteQueueSelector localWriteQueueSelector; public LocalGrpcService(BrokerController brokerController) { this(brokerController, new TelemetryCommandManager()); @@ -140,6 +146,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); + this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), + brokerController.getTopicConfigManager(), connectorManager.getTopicRouteCache()); this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); @@ -208,10 +216,11 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName); + MessageQueue messageQueue = localWriteQueueSelector.selectQueue(ctx, request).getMessageQueue(); + String topicName = messageQueue.getTopic(); + SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName, messageQueue.getQueueId()); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); - List messageList = GrpcConverter.buildMessage(request.getMessagesList(), topicName); + List messageList = GrpcConverter.buildMessage(request.getMessagesList(), request.getMessages(0).getTopic()); String messageId; if (messageList.size() == 1) { org.apache.rocketmq.common.message.Message message = messageList.get(0); @@ -254,7 +263,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo } @Override - public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { + public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); // TODO: get fifo config from subscriptionGroupManager boolean fifo = false; @@ -265,8 +274,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture future = new CompletableFuture<>(); - InvocationContext context + CompletableFuture> future = new CompletableFuture<>(); + InvocationContext> context = new InvocationContext<>(request, future); channel.registerInvocationContext(command.getOpaque(), context); try { @@ -280,7 +289,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } - return future; + future.thenAccept(r -> ResponseWriter.write(responseObserver, r)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(e)).build() + ); + return null; + }); } @Override @@ -329,7 +345,8 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); - int maxReconsumeTimes = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy().getMaxAttempts(); + RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy(); + int maxReconsumeTimes = retryPolicy.getMaxAttempts(); if (request.getDeliveryAttempt() >= maxReconsumeTimes) { ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); @@ -347,7 +364,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo future.completeExceptionally(e); } } else { - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, delayPolicy); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, retryPolicy); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); command.makeCustomHeaderToNet(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java new file mode 100644 index 0000000000..8880b83e9c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.service.local; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.SendMessageRequest; +import com.google.common.hash.Hashing; +import io.grpc.Context; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.broker.topic.TopicConfigManager; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultWriteQueueSelector; + +public class LocalWriteQueueSelector extends DefaultWriteQueueSelector { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private final String brokerName; + private final AtomicInteger queueIndex; + private final TopicConfigManager topicConfigManager; + + public LocalWriteQueueSelector(String brokerName, TopicConfigManager topicConfigManager, TopicRouteCache topicRouteCache) { + super(topicRouteCache); + this.brokerName = brokerName; + this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); + this.topicConfigManager = topicConfigManager; + } + + @Override + public SelectableMessageQueue selectQueue( + Context ctx, + SendMessageRequest request + ) { + try { + if (request.getMessagesCount() <= 0) { + throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); + } + Message message = request.getMessages(0); + String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); + String shardingKey = null; + if (request.getMessagesCount() == 1) { + shardingKey = message.getSystemProperties().getMessageGroup(); + } + SelectableMessageQueue targetMessageQueue; + if (StringUtils.isNotEmpty(shardingKey)) { + // With shardingKey + targetMessageQueue = selectOrderQueue(topic, shardingKey); + } else { + targetMessageQueue = selectNormalQueue(topic); + } + return targetMessageQueue; + } catch (Exception e) { + log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); + return null; + } + } + + protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { + TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); + if (topicConfig == null) { + throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); + } + int selectQueueId = queueIndex.getAndIncrement() % topicConfig.getWriteQueueNums(); + MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); + return new SelectableMessageQueue(mq, null); + } + + protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { + TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); + if (topicConfig == null) { + throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); + } + int selectQueueId = Hashing.consistentHash(shardingKey.hashCode(), topicConfig.getWriteQueueNums()); + MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); + return new SelectableMessageQueue(mq, null); + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 8c93da865d..7639729f38 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -48,9 +48,9 @@ import apache.rocketmq.v2.SystemProperties; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; -import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.Metadata; +import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import io.netty.channel.ChannelHandlerContext; import java.net.InetSocketAddress; @@ -71,8 +71,10 @@ import org.apache.rocketmq.broker.processor.EndTransactionProcessor; import org.apache.rocketmq.broker.processor.PopMessageProcessor; import org.apache.rocketmq.broker.processor.PullMessageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.broker.topic.TopicConfigManager; import org.apache.rocketmq.common.BrokerConfig; import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; @@ -83,6 +85,7 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; @@ -95,6 +98,7 @@ import org.apache.rocketmq.store.config.MessageStoreConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; @@ -117,10 +121,14 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { private ConsumerManager consumerManagerMock; @Mock private ProducerManager producerManagerMock; + @Mock + private TopicConfigManager topicConfigManagerMock; @Mock private TelemetryCommandManager telemetryCommandManager; + StreamObserver receiveStreamObserver = Mockito.mock(ServerCallStreamObserver.class); + private Metadata metadata; private StreamObserver streamObserver; @@ -128,10 +136,13 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { @Before public void setUp() throws Throwable { super.before(); + ConfigurationManager.getProxyConfig().setNameSrvAddr("1.1.1.1"); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); Mockito.when(brokerControllerMock.getMessageStoreConfig()).thenReturn(new MessageStoreConfig()); + Mockito.when(brokerControllerMock.getTopicConfigManager()).thenReturn(topicConfigManagerMock); + Mockito.when(topicConfigManagerMock.selectTopicConfig(Mockito.anyString())).thenReturn(new TopicConfig("topic", 8, 8)); Mockito.doNothing().when(consumerManagerMock).appendConsumerIdsChangeListener(Mockito.any(ConsumerIdsChangeListener.class)); Mockito.doNothing().when(producerManagerMock).appendProducerChangeListener(Mockito.any(ProducerChangeListener.class)); Mockito.when(brokerControllerMock.getConsumerManager()).thenReturn(consumerManagerMock); @@ -320,29 +331,26 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build()) .build()) .build(); - CompletableFuture grpcFuture = localGrpcService.receiveMessage( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))), request); - ReceiveMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - assertThat(r.getMessagesCount()).isEqualTo(1); - assertThat(Durations.toMillis(r.getInvisibleDuration())).isEqualTo(invisibleTime); - assertThat(GrpcConverter.wrapResourceWithNamespace(r.getMessages(0).getTopic())).isEqualTo(topic); - assertThat(r.getMessages(0).getBody().toByteArray()).isEqualTo(body); - } - - @Test - public void testReceiveMessageSuccessWriteAndFlush() throws Exception { - Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(null); - ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder().getDefaultInstanceForType(); - CompletableFuture grpcFuture = localGrpcService.receiveMessage( - Context.current() - .withDeadlineAfter(20, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("test"))), request); - assertThat(grpcFuture.isDone()).isFalse(); + ReceiveMessageResponse receiveMessageResponse1 = ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, null)) + .build(); + Message message = GrpcConverter.buildMessage(messageExt); + ReceiveMessageResponse receiveMessageResponse2 = ReceiveMessageResponse.newBuilder() + .setMessage(message.toBuilder() + .setSystemProperties( + message.getSystemProperties() + .toBuilder() + .setReceiptHandle("0 0 1000 0 0 zhouxiang_MBP16 0 0 0") + .build()) + .build()) + .build(); + Mockito.doNothing().when(receiveStreamObserver).onNext(Mockito.any()); + localGrpcService.receiveMessage(Context.current().withDeadlineAfter(20, TimeUnit.SECONDS, + Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("test"))), request, receiveStreamObserver); + ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + Mockito.verify(receiveStreamObserver, Mockito.times(2)).onNext(argument.capture()); + assertThat(argument.getAllValues().get(0)).isEqualTo(receiveMessageResponse1); + assertThat(argument.getAllValues().get(1)).isEqualTo(receiveMessageResponse2); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java new file mode 100644 index 0000000000..bacf434fd5 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java @@ -0,0 +1,78 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SystemProperties; +import io.grpc.Context; +import org.apache.rocketmq.broker.topic.TopicConfigManager; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LocalWriteQueueSelectorTest { + private LocalWriteQueueSelector localWriteQueueSelector; + private String topic = "test-topic"; + private String brokerName = "broker"; + private int writeQueueId = 8; + private String messageGroup = "message-group"; + + @Before + public void setup() { + TopicConfigManager topicConfigManager = Mockito.mock(TopicConfigManager.class); + TopicConfig topicConfig = new TopicConfig(topic, writeQueueId, writeQueueId); + Mockito.when(topicConfigManager.selectTopicConfig(topic)).thenReturn(topicConfig); + localWriteQueueSelector = new LocalWriteQueueSelector(brokerName, topicConfigManager, null); + } + + @Test + public void testSelectQueueWithNormalMessage() { + SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder().setTopic(Resource.newBuilder().setName(topic).build())) + .build(); + SelectableMessageQueue selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); + assertThat(selectableMessageQueue.getBrokerName()).isEqualTo(brokerName); + assertThat(selectableMessageQueue.getTopic()).isEqualTo(topic); + int selectQueueId = selectableMessageQueue.getQueueId(); + selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); + assertThat(selectableMessageQueue.getQueueId()).isEqualTo((selectQueueId + 1) % writeQueueId); + } + + @Test + public void testSelectQueueWithFifoMessage() { + SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageGroup(messageGroup) + .build()) + .setTopic(Resource.newBuilder().setName(topic).build())) + .build(); + SelectableMessageQueue selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); + assertThat(selectableMessageQueue.getBrokerName()).isEqualTo(brokerName); + assertThat(selectableMessageQueue.getTopic()).isEqualTo(topic); + int selectQueueId = selectableMessageQueue.getQueueId(); + selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); + assertThat(selectableMessageQueue.getQueueId()).isEqualTo(selectQueueId); + } +} \ No newline at end of file From 1667fb81f479b901f5ca1d87564012653822727c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 26 Apr 2022 11:15:32 +0800 Subject: [PATCH 134/338] [ISSUE #3949] v2 support --- .../proxy/grpc/v2/adapter/ResponseWriter.java | 34 ++- .../v2/service/cluster/ConsumerService.java | 90 ++------ ...ultReceiveMessageResponseStreamWriter.java | 211 ++++++++++++++++++ .../ReceiveMessageResponseStreamObserver.java | 61 ----- .../ReceiveMessageResponseStreamWriter.java | 47 ++++ .../service/cluster/ConsumerServiceTest.java | 3 +- 6 files changed, 296 insertions(+), 150 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 9ce43db169..28efb42ae4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -19,7 +19,6 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; -import java.util.Iterator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -27,13 +26,6 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - public static void write(StreamObserver observer, final Iterator responseIterator) { - while (responseIterator.hasNext()) { - writeResponse(observer, responseIterator.next()); - } - observer.onCompleted(); - } - public static void write(StreamObserver observer, final T response) { writeResponse(observer, response); observer.onCompleted(); @@ -43,12 +35,9 @@ public class ResponseWriter { if (null == response) { return; } - if (observer instanceof ServerCallStreamObserver) { - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; - if (serverCallStreamObserver.isCancelled()) { - log.warn("client has cancelled the request. response to write: {}", response); - return; - } + if (isCancelled(observer)) { + log.warn("client has cancelled the request. response to write: {}", response); + return; } log.debug("start to write response. response: {}", response); observer.onNext(response); @@ -58,16 +47,21 @@ public class ResponseWriter { if (null == e) { return; } - if (observer instanceof ServerCallStreamObserver) { - final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; - if (serverCallStreamObserver.isCancelled()) { - log.warn("Client has cancelled the request. Exception to write", e); - return; - } + if (isCancelled(observer)) { + log.warn("Client has cancelled the request. Exception to write", e); + return; } log.debug("Start to write error response", e); observer.onError(e); observer.onCompleted(); } + + public static boolean isCancelled(StreamObserver observer) { + if (observer instanceof ServerCallStreamObserver) { + final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; + return serverCallStreamObserver.isCancelled(); + } + return false; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 62b7d73597..f8c77cd896 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -23,7 +23,6 @@ import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -37,8 +36,6 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.client.consumer.PopResult; -import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; @@ -53,7 +50,6 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -67,7 +63,8 @@ public class ConsumerService extends BaseService { protected final GrpcClientManager grpcClientManager; private volatile ReadQueueSelector readQueueSelector; - private volatile ReceiveMessageResultFilter receiveMessageResultFilter; + private volatile ReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; + private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackMessageHook; private volatile ResponseHook nackMessageHook; @@ -84,17 +81,19 @@ public class ConsumerService extends BaseService { @Override public void start() throws Exception { this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); - this.receiveMessageResultFilter = new DefaultReceiveMessageResultFilter( - producer, writeConsumer, grpcClientManager, connectorManager.getTopicRouteCache()); + this.receiveMessageWriterBuilder = (observer, hook) -> new DefaultReceiveMessageResponseStreamWriter( + observer, + hook, + writeConsumer, + connectorManager.getTopicRouteCache(), + new DefaultReceiveMessageResultFilter( + producer, writeConsumer, grpcClientManager, connectorManager.getTopicRouteCache()) + ); } public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - ReceiveMessageResponseStreamObserver streamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - responseObserver); + ReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); try { PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); @@ -109,10 +108,13 @@ public class ConsumerService extends BaseService { messageQueue.getBrokerName(), requestHeader, requestHeader.getPollTime()) - .thenAccept(result -> writeReceiveMessageResponse(ctx, request, result, streamObserver)) - .exceptionally(e -> writeReceiveMessageResponse(ctx, e, streamObserver)); + .thenAccept(result -> writer.write(ctx, request, result)) + .exceptionally(e -> { + writer.write(ctx, request, e); + return null; + }); } catch (Throwable t) { - writeReceiveMessageResponse(ctx, t, streamObserver); + writer.write(ctx, request, t); } } @@ -122,54 +124,6 @@ public class ConsumerService extends BaseService { return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); } - protected void writeReceiveMessageResponse(Context ctx, ReceiveMessageRequest request, - PopResult result, StreamObserver streamObserver) { - PopStatus status = result.getPopStatus(); - try { - switch (status) { - case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); - if (messageList.isEmpty()) { - streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - } else { - streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - for (Message message : messageList) { - streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setMessage(message) - .build()); - } - } - break; - case POLLING_FULL: - streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build()); - break; - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - break; - } - } finally { - streamObserver.onCompleted(); - } - } - - protected Void writeReceiveMessageResponse(Context ctx, Throwable throwable, StreamObserver streamObserver) { - ResponseWriter.write( - streamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() - ); - return null; - } - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -364,13 +318,13 @@ public class ConsumerService extends BaseService { this.readQueueSelector = readQueueSelector; } - public ReceiveMessageResultFilter getReceiveMessageResultFilter() { - return receiveMessageResultFilter; + public ReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { + return receiveMessageWriterBuilder; } - public void setReceiveMessageResultFilter( - ReceiveMessageResultFilter receiveMessageResultFilter) { - this.receiveMessageResultFilter = receiveMessageResultFilter; + public void setReceiveMessageWriterBuilder( + ReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { + this.receiveMessageWriterBuilder = receiveMessageWriterBuilder; } public ResponseHook getReceiveMessageHook() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..7a1043f29d --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -0,0 +1,211 @@ +/* + * 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.grpc.v2.service.cluster; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.time.Duration; +import java.util.Iterator; +import java.util.List; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; + +public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); + protected final ForwardWriteConsumer writeConsumer; + protected final TopicRouteCache topicRouteCache; + protected volatile ReceiveMessageResultFilter receiveMessageResultFilter; + + public DefaultReceiveMessageResponseStreamWriter( + StreamObserver observer, + ResponseHook hook, + ForwardWriteConsumer writeConsumer, + TopicRouteCache topicRouteCache, + ReceiveMessageResultFilter receiveMessageResultFilter) { + super(observer, hook); + this.writeConsumer = writeConsumer; + this.topicRouteCache = topicRouteCache; + this.receiveMessageResultFilter = receiveMessageResultFilter; + } + + @Override + public void write(Context ctx, ReceiveMessageRequest request, PopResult result) { + PopStatus status = result.getPopStatus(); + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + try { + switch (status) { + case FOUND: + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); + if (messageList.isEmpty()) { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + } else { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + Iterator messageIterator = messageList.iterator(); + while (messageIterator.hasNext()) { + if (responseStreamObserver.isCancelled()) { + break; + } + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setMessage(messageIterator.next()) + .build()); + } + messageIterator.forEachRemaining(message -> { + this.nackFailToWriteMessage(ctx, request, message); + }); + } + break; + case POLLING_FULL: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .build()); + break; + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + break; + } + } finally { + responseStreamObserver.onCompleted(); + } + } + + @Override + public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + ResponseWriter.write( + responseStreamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() + ); + } + + protected void nackFailToWriteMessage(Context ctx, ReceiveMessageRequest request, Message message) { + try { + String receiptHandleStr = message.getSystemProperties().getReceiptHandle(); + ReceiptHandle handle = BaseService.resolveReceiptHandle(ctx, receiptHandleStr); + String brokerAddr = BaseService.getBrokerAddr(ctx, this.topicRouteCache, handle.getBrokerName()); + + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(NACK_INVISIBLE_TIME); + + this.writeConsumer.changeInvisibleTimeAsync( + ctx, + brokerAddr, + handle.getBrokerName(), + changeInvisibleTimeRequestHeader + ).whenComplete((ackResult, t) -> { + if (t != null) { + log.warn("err when nack message. request:{}, message:{}", request, message, t); + } else if (!AckStatus.OK.equals(ackResult.getStatus())) { + log.warn("nack failed. request:{}, message:{}, ackResult:{}", request, message, ackResult); + } + }); + } catch (Throwable t) { + log.warn("err when nack message. request:{}, message:{}", request, message, t); + } + } + + protected static class ReceiveMessageResponseStreamObserver implements StreamObserver { + + private final Context context; + private final ReceiveMessageRequest request; + private final ResponseHook receiveMessageHook; + private final StreamObserver observer; + + public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, + ResponseHook receiveMessageHook, + StreamObserver observer) { + this.context = context; + this.request = request; + this.receiveMessageHook = receiveMessageHook; + this.observer = observer; + } + + @Override + public void onNext(ReceiveMessageResponse response) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, response, null); + } + observer.onNext(response); + } + + @Override + public void onError(Throwable throwable) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, null, throwable); + } + observer.onError(throwable); + } + + @Override + public void onCompleted() { + observer.onCompleted(); + } + + public boolean isCancelled() { + return ResponseWriter.isCancelled(observer); + } + } + + public ReceiveMessageResultFilter getReceiveMessageResultFilter() { + return receiveMessageResultFilter; + } + + public void setReceiveMessageResultFilter( + ReceiveMessageResultFilter receiveMessageResultFilter) { + this.receiveMessageResultFilter = receiveMessageResultFilter; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java deleted file mode 100644 index d6946efb1b..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamObserver.java +++ /dev/null @@ -1,61 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; - -public class ReceiveMessageResponseStreamObserver implements StreamObserver { - - private final Context context; - private final ReceiveMessageRequest request; - private final ResponseHook receiveMessageHook; - private final StreamObserver observer; - - public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, - ResponseHook receiveMessageHook, - StreamObserver observer) { - this.context = context; - this.request = request; - this.receiveMessageHook = receiveMessageHook; - this.observer = observer; - } - - @Override - public void onNext(ReceiveMessageResponse response) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, response, null); - } - observer.onNext(response); - } - - @Override - public void onError(Throwable throwable) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, null, throwable); - } - observer.onError(throwable); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } -} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..c1d0625165 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.service.cluster; + +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; + +public abstract class ReceiveMessageResponseStreamWriter { + + protected final StreamObserver streamObserver; + protected final ResponseHook receiveMessageHook; + + public interface Builder { + ReceiveMessageResponseStreamWriter build( + StreamObserver observer, + ResponseHook hook); + } + + public ReceiveMessageResponseStreamWriter( + StreamObserver observer, + ResponseHook hook) { + streamObserver = observer; + receiveMessageHook = hook; + } + + public abstract void write(Context ctx, ReceiveMessageRequest request, PopResult result); + + public abstract void write(Context ctx, ReceiveMessageRequest request, Throwable throwable); +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 35ed62dd26..eb3190151e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -66,7 +66,8 @@ public class ConsumerServiceTest extends BaseServiceTest { consumerService.start(); receiveMessageResultFilter = new DefaultReceiveMessageResultFilter(producerClient, writeConsumerClient, grpcClientManager, topicRouteCache); - consumerService.setReceiveMessageResultFilter(receiveMessageResultFilter); + consumerService.setReceiveMessageWriterBuilder((observer, hook) -> + new DefaultReceiveMessageResponseStreamWriter(observer, hook, writeConsumerClient, topicRouteCache, receiveMessageResultFilter)); consumerService.setReadQueueSelector(readQueueSelector); } From 03a10d56086d8ea3f547a017c3cf7deda2b3083a Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 26 Apr 2022 16:13:43 +0800 Subject: [PATCH 135/338] [ISSUE #3949] Add local/RouteService --- .../grpc/v2/service/AbstractRouteService.java | 100 ++++++++++ .../grpc/v2/service/LocalGrpcService.java | 5 +- .../grpc/v2/service/cluster/RouteService.java | 69 +------ .../grpc/v2/service/local/RouteService.java | 175 ++++++++++++++++++ .../v2/service/local/RouteServiceTest.java | 132 +++++++++++++ 5 files changed, 413 insertions(+), 68 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java new file mode 100644 index 0000000000..d582d718a2 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java @@ -0,0 +1,100 @@ +/* + * 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.grpc.v2.service; + +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.common.ParameterConverter; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.AssignmentQueueSelector; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseService; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultAssignmentQueueSelector; + +public abstract class AbstractRouteService extends BaseService { + protected volatile ParameterConverter queryRouteEndpointConverter; + protected volatile ResponseHook queryRouteHook; + + protected volatile ParameterConverter queryAssignmentEndpointConverter; + protected volatile ResponseHook queryAssignmentHook; + protected volatile AssignmentQueueSelector assignmentQueueSelector; + + protected final GrpcClientManager grpcClientManager; + + public AbstractRouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { + super(connectorManager); + this.grpcClientManager = grpcClientManager; + this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; + this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; + this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); + } + + public abstract CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); + + public abstract CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); + + public ParameterConverter getQueryRouteEndpointConverter() { + return queryRouteEndpointConverter; + } + + public void setQueryRouteEndpointConverter( + ParameterConverter queryRouteEndpointConverter) { + this.queryRouteEndpointConverter = queryRouteEndpointConverter; + } + + public ResponseHook getQueryRouteHook() { + return queryRouteHook; + } + + public void setQueryRouteHook( + ResponseHook queryRouteHook) { + this.queryRouteHook = queryRouteHook; + } + + public ParameterConverter getQueryAssignmentEndpointConverter() { + return queryAssignmentEndpointConverter; + } + + public void setQueryAssignmentEndpointConverter( + ParameterConverter queryAssignmentEndpointConverter) { + this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; + } + + public AssignmentQueueSelector getAssignmentQueueSelector() { + return assignmentQueueSelector; + } + + public void setAssignmentQueueSelector( + AssignmentQueueSelector assignmentQueueSelector) { + this.assignmentQueueSelector = assignmentQueueSelector; + } + + public ResponseHook getQueryAssignmentHook() { + return queryAssignmentHook; + } + + public void setQueryAssignmentHook( + ResponseHook queryAssignmentHook) { + this.queryAssignmentHook = queryAssignmentHook; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 920c5b2938..070c1e7a4c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -98,7 +98,6 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; @@ -106,7 +105,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; @@ -143,7 +142,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ConnectorManager connectorManager = new ConnectorManager(null); this.telemetryCommandManager = telemetryCommandManager; this.grpcClientManager = new GrpcClientManager(); - this.routeService = new RouteService(ProxyMode.LOCAL, connectorManager, grpcClientManager); + this.routeService = new RouteService(connectorManager, grpcClientManager); this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index d91bcb4ccc..e8c206b609 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -33,38 +33,21 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.common.ParameterConverter; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -public class RouteService extends BaseService { - private volatile ParameterConverter queryRouteEndpointConverter; - private volatile ResponseHook queryRouteHook; - - private volatile ParameterConverter queryAssignmentEndpointConverter; - private volatile AssignmentQueueSelector assignmentQueueSelector; - private volatile ResponseHook queryAssignmentHook; - - protected final GrpcClientManager grpcClientManager; - +public class RouteService extends AbstractRouteService { public RouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { - super(connectorManager); - this.grpcClientManager = grpcClientManager; + super(connectorManager, grpcClientManager); } @Override - public void start() throws Exception { - this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; - this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; - this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); - } - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -115,6 +98,7 @@ public class RouteService extends BaseService { return future; } + @Override public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { CompletableFuture future = new CompletableFuture<>(); future.whenComplete((response, throwable) -> { @@ -164,49 +148,4 @@ public class RouteService extends BaseService { } return future; } - - public ParameterConverter getQueryRouteEndpointConverter() { - return queryRouteEndpointConverter; - } - - public void setQueryRouteEndpointConverter( - ParameterConverter queryRouteEndpointConverter) { - this.queryRouteEndpointConverter = queryRouteEndpointConverter; - } - - public ResponseHook getQueryRouteHook() { - return queryRouteHook; - } - - public void setQueryRouteHook( - ResponseHook queryRouteHook) { - this.queryRouteHook = queryRouteHook; - } - - public ParameterConverter getQueryAssignmentEndpointConverter() { - return queryAssignmentEndpointConverter; - } - - public void setQueryAssignmentEndpointConverter( - ParameterConverter queryAssignmentEndpointConverter) { - this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; - } - - public AssignmentQueueSelector getAssignmentQueueSelector() { - return assignmentQueueSelector; - } - - public void setAssignmentQueueSelector( - AssignmentQueueSelector assignmentQueueSelector) { - this.assignmentQueueSelector = assignmentQueueSelector; - } - - public ResponseHook getQueryAssignmentHook() { - return queryAssignmentHook; - } - - public void setQueryAssignmentHook( - ResponseHook queryAssignmentHook) { - this.queryAssignmentHook = queryAssignmentHook; - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java new file mode 100644 index 0000000000..7083f0684a --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java @@ -0,0 +1,175 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Assignment; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.Permission; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import com.google.common.net.HostAndPort; +import io.grpc.Context; +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.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.connector.ConnectorManager; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; + +public class RouteService extends AbstractRouteService { + public RouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { + super(connectorManager, grpcClientManager); + } + + @Override + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (queryRouteHook != null) { + queryRouteHook.beforeResponse(ctx, request, response, throwable); + } + }); + + try { + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); + TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); + List queueDataList = topicRouteData.getQueueDatas(); + List brokerDataList = topicRouteData.getBrokerDatas(); + + List messageQueueList = new ArrayList<>(); + Map> brokerMap = buildBrokerMap(brokerDataList); + + for (QueueData queueData : queueDataList) { + String brokerName = queueData.getBrokerName(); + Map brokerIdMap = brokerMap.get(brokerName); + if (brokerIdMap == null) { + break; + } + for (Broker broker : brokerIdMap.values()) { + messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); + } + } + + QueryRouteResponse response = QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllMessageQueues(messageQueueList) + .build(); + future.complete(response); + } catch (Throwable t) { + if (TopicRouteHelper.isTopicNotExistError(t)) { + future.complete(QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) + .build()); + } else { + future.completeExceptionally(t); + } + } + return future; + } + + @Override + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + CompletableFuture future = new CompletableFuture<>(); + future.whenComplete((response, throwable) -> { + if (queryAssignmentHook != null) { + queryAssignmentHook.beforeResponse(ctx, request, response, throwable); + } + }); + + try { + List assignments = new ArrayList<>(); + List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); + MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); + TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); + Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); + for (SelectableMessageQueue messageQueue : messageQueueList) { + Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); + if (brokerIdMap != null) { + Broker broker = brokerIdMap.get(0L); + + MessageQueue defaultMessageQueue = MessageQueue.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(Permission.READ_WRITE) + .setBroker(broker) + .build(); + + assignments.add(Assignment.newBuilder() + .setMessageQueue(defaultMessageQueue) + .build()); + } + } + QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() + .addAllAssignments(assignments) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build(); + future.complete(response); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + private Map> buildBrokerMap(List brokerDataList) { + Map> brokerMap = new HashMap<>(); + for (BrokerData brokerData : brokerDataList) { + Map brokerIdMap = new HashMap<>(); + String brokerName = brokerData.getBrokerName(); + for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { + Long brokerId = entry.getKey(); + HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); + Broker broker = Broker.newBuilder() + .setName(brokerName) + .setId(Math.toIntExact(brokerId)) + .setEndpoints(Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses( + Address.newBuilder() + .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) + .setHost(hostAndPort.getHost()) + ) + .build()) + .build(); + + brokerIdMap.put(brokerId, broker); + } + brokerMap.put(brokerName, brokerIdMap); + } + return brokerMap; + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java new file mode 100644 index 0000000000..25078d4a89 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java @@ -0,0 +1,132 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import com.google.common.net.HostAndPort; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseServiceTest; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class RouteServiceTest extends BaseServiceTest { + private String brokerAddress = "127.0.0.1:10911"; + private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() + .setAccessPoint(Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") + .build()) + .setScheme(AddressScheme.DOMAIN_NAME) + .build()) + .build(); + + @Test + public void testLocalModeQueryRoute() throws Exception { + RouteService routeService = new RouteService(this.connectorManager, this.grpcClientManager); + routeService.start(); + + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); + + CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .build()); + QueryRouteResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); + assertEquals(8, response.getMessageQueuesCount()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getMessageQueues(0).getBroker() + .getEndpoints().getAddresses(0).getHost()); + } + + @Test + public void testLocalModeQueryAssignment() throws Exception { + RouteService routeService = new RouteService(this.connectorManager, this.grpcClientManager); + routeService.start(); + + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); + + CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .build()); + + QueryAssignmentResponse response = future.get(); + assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); + assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); + } + + @Override public void beforeEach() throws Throwable { + TopicRouteData routeData = new TopicRouteData(); + + List brokerDataList = new ArrayList<>(); + BrokerData brokerData = new BrokerData(); + brokerData.setCluster("cluster"); + brokerData.setBrokerName("brokerName"); + HashMap brokerAddrs = new HashMap() {{ + put(0L, brokerAddress); + }}; + brokerData.setBrokerAddrs(brokerAddrs); + brokerDataList.add(brokerData); + + List queueDataList = new ArrayList<>(); + QueueData queueData = new QueueData(); + queueData.setPerm(6); + queueData.setWriteQueueNums(8); + queueData.setReadQueueNums(8); + queueData.setBrokerName("brokerName"); + queueDataList.add(queueData); + + routeData.setBrokerDatas(brokerDataList); + routeData.setQueueDatas(queueDataList); + + MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); + when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); + + when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + } +} \ No newline at end of file From fa26627138937c133ef3732944b69197d49a5c89 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 26 Apr 2022 16:25:54 +0800 Subject: [PATCH 136/338] [ISSUE #3949] v2 support --- .../rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java | 8 ++++++++ .../proxy/grpc/v2/service/AbstractRouteService.java | 1 - .../proxy/grpc/v2/service/{cluster => }/BaseService.java | 2 +- .../proxy/grpc/v2/service/cluster/ConsumerService.java | 4 +--- .../DefaultReceiveMessageResponseStreamWriter.java | 5 ++--- .../cluster/DefaultReceiveMessageResultFilter.java | 6 ++---- .../grpc/v2/service/cluster/ForwardClientService.java | 4 +--- .../proxy/grpc/v2/service/cluster/ProducerService.java | 4 +--- .../proxy/grpc/v2/service/cluster/TransactionService.java | 1 + 9 files changed, 17 insertions(+), 18 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/{cluster => }/BaseService.java (98%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java index 28efb42ae4..90f1bfaa77 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; +import java.util.Iterator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -26,6 +27,13 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + public static void write(StreamObserver observer, final Iterator response) { + while (response.hasNext()) { + writeResponse(observer, response.next()); + } + observer.onCompleted(); + } + public static void write(StreamObserver observer, final T response) { writeResponse(observer, response); observer.onCompleted(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java index d582d718a2..307d9cea42 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java @@ -28,7 +28,6 @@ import org.apache.rocketmq.proxy.common.ParameterConverter; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.AssignmentQueueSelector; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultAssignmentQueueSelector; public abstract class AbstractRouteService extends BaseService { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java index 9843cf7d3a..8d2a923323 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index f8c77cd896..0714b5bb23 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -50,6 +50,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -76,10 +77,7 @@ public class ConsumerService extends BaseService { this.writeConsumer = connectorManager.getForwardWriteConsumer(); this.producer = connectorManager.getForwardProducer(); this.grpcClientManager = grpcClientManager; - } - @Override - public void start() throws Exception { this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); this.receiveMessageWriterBuilder = (observer, hook) -> new DefaultReceiveMessageResponseStreamWriter( observer, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index 7a1043f29d..a15e436739 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -39,6 +39,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -89,9 +90,7 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes .setMessage(messageIterator.next()) .build()); } - messageIterator.forEachRemaining(message -> { - this.nackFailToWriteMessage(ctx, request, message); - }); + messageIterator.forEachRemaining(message -> this.nackFailToWriteMessage(ctx, request, message)); } break; case POLLING_FULL: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java index 15b5b35c69..ba50750a16 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; @@ -42,7 +41,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import static org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseService.getBrokerAddr; +import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFilter { @@ -68,7 +67,6 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi return Collections.emptyList(); } Settings settings = grpcClientManager.getClientSettings(ctx); - ClientType clientType = settings.getClientType(); int maxAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); Resource topic = request.getMessageQueue().getTopic(); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); @@ -76,7 +74,7 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi List resMessageList = new ArrayList<>(); for (MessageExt messageExt : messageExtList) { - if (ClientType.SIMPLE_CONSUMER.equals(clientType) && messageExt.getReconsumeTimes() >= maxAttempts) { + if (messageExt.getReconsumeTimes() >= maxAttempts) { forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); continue; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java index 0c7fde9b43..d3898bee4d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java @@ -51,6 +51,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; import org.apache.rocketmq.remoting.protocol.LanguageCode; @@ -82,10 +83,7 @@ public class ForwardClientService extends BaseService { this.channelManager = channelManager; this.grpcClientManager = grpcClientManager; this.telemetryCommandManager = telemetryCommandManager; - } - @Override - public void start() throws Exception { this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); this.producerManager = new ProducerManager(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java index 8bb0b3909e..9fd4ea8e44 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java @@ -41,6 +41,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerService extends BaseService { @@ -53,10 +54,7 @@ public class ProducerService extends BaseService { public ProducerService(ConnectorManager connectorManager) { super(connectorManager); this.producer = connectorManager.getForwardProducer(); - } - @Override - public void start() throws Exception { this.writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index eb71fa848e..d142e2de98 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -38,6 +38,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.remoting.common.RemotingHelper; public class TransactionService extends BaseService implements TransactionStateChecker { From b94dcd0a60433d8c57677fec348e1ac292fe5c5e Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 27 Apr 2022 09:56:19 +0800 Subject: [PATCH 137/338] [ISSUE #3949] fix to fit checkStyle. --- proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java | 2 +- .../apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java | 1 - .../rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) 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 516a99506a..55f7526e58 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -81,7 +81,7 @@ public class ProxyStartup { System.exit(1); } - System.out.println(new Date() + " rmq-proxy startup successfully"); + System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); log.info(new Date() + " rmq-proxy startup successfully"); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index 586061b3e4..ad06e23074 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -44,7 +44,6 @@ import apache.rocketmq.v2.Status; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; -import java.util.Iterator; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index bea689d077..40258fbb83 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -56,7 +56,6 @@ import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; From de94a7065275ab69b91bb2a4689c73caab5163d9 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 27 Apr 2022 16:17:28 +0800 Subject: [PATCH 138/338] [ISSUE #3949] v2 support --- .../apache/rocketmq/proxy/ProxyStartup.java | 4 +-- .../proxy/config/ConfigurationManager.java | 4 +-- .../rocketmq/proxy/grpc/GrpcServer.java | 34 ++++++++++++------- .../grpc/v2/service/GrpcClientManager.java | 32 ++++++++--------- .../grpc/v2/service/LocalGrpcService.java | 2 +- .../v2/service/cluster/ConsumerService.java | 4 +-- ...ultReceiveMessageResponseStreamWriter.java | 2 ++ .../DefaultReceiveMessageResultFilter.java | 2 +- .../grpc/v2/service/LocalGrpcServiceTest.java | 6 ++-- .../service/cluster/ConsumerServiceTest.java | 9 ++--- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 12 +++---- 11 files changed, 61 insertions(+), 50 deletions(-) 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 55f7526e58..c34d947ab2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -117,13 +117,13 @@ public class ProxyStartup { return BrokerStartup.createBrokerController(brokerStartupArgs); } - private static void initThreadPoolMonitor() { + public static void initThreadPoolMonitor() { ThreadPoolMonitor.init(); ProxyConfig config = ConfigurationManager.getProxyConfig(); ThreadPoolMonitor.config(config.isEnablePrintJstack(), config.getPrintJstackInMillis()); } - private static void initLogger() throws JoranException { + public static void initLogger() throws JoranException { System.setProperty("brokerLogDir", ""); System.setProperty(ClientLogger.CLIENT_LOG_USESLF4J, "true"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java index fd4d600f4e..6efecf5e73 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java @@ -23,8 +23,8 @@ import org.apache.commons.lang3.StringUtils; public class ConfigurationManager { public static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; protected static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; - private static String proxyHome; - private static Configuration configuration; + protected static String proxyHome; + protected static Configuration configuration; public static void initEnv() { proxyHome = System.getenv(RMQ_PROXY_HOME); 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 eca8012811..78e3770659 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 @@ -79,7 +79,7 @@ public class GrpcServer implements StartAndShutdown { threadPoolQueueCapacity ); - GrpcMessagingProcessor messagingProcessor = new GrpcMessagingProcessor(grpcForwardService); + GrpcMessagingProcessor messagingProcessor = createProcessor(); // build server int bossLoopNum = ConfigurationManager.getProxyConfig().getGrpcBossLoopNum(); @@ -102,18 +102,8 @@ public class GrpcServer implements StartAndShutdown { .executor(this.executor); } - // grpc interceptors, including acl, logging etc. - if (ConfigurationManager.getProxyConfig().isEnableACL()) { - List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); - if (accessValidators.isEmpty()) { - throw new IllegalArgumentException("Load AccessValidator failed"); - } - serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); - } - - this.server = serverBuilder.intercept(new ContextInterceptor()) - .intercept(new HeaderInterceptor()) - .build(); + configInterceptor(serverBuilder); + this.server = serverBuilder.build(); log.info( "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " @@ -122,6 +112,10 @@ public class GrpcServer implements StartAndShutdown { bossLoopNum, workerLoopNum, maxInboundMessageSize); } + protected GrpcMessagingProcessor createProcessor() { + return new GrpcMessagingProcessor(grpcForwardService); + } + protected void configSslContext(NettyServerBuilder serverBuilder) throws SSLException, CertificateException { if (null == serverBuilder) { return; @@ -151,6 +145,20 @@ public class GrpcServer implements StartAndShutdown { } } + protected void configInterceptor(NettyServerBuilder serverBuilder) { + // grpc interceptors, including acl, logging etc. + if (ConfigurationManager.getProxyConfig().isEnableACL()) { + List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); + if (accessValidators.isEmpty()) { + throw new IllegalArgumentException("Load AccessValidator failed"); + } + serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); + } + + serverBuilder.intercept(new ContextInterceptor()) + .intercept(new HeaderInterceptor()); + } + public void start() throws Exception { // first to start grpc service. this.grpcForwardService.start(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java index 86eab3a26d..e0088cd8b8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java @@ -33,30 +33,30 @@ public class GrpcClientManager { // TODO: read config from topic or subscription configManager protected static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() - .setPublishing(Publishing.newBuilder() - .setRetryPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(3) - .setExponentialBackoff(ExponentialBackoff.newBuilder() - .setInitial(Durations.fromSeconds(1)) - .setMax(Durations.fromSeconds(3)) - .setMultiplier(2) - .build()) + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(3) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setInitial(Durations.fromSeconds(1)) + .setMax(Durations.fromSeconds(3)) + .setMultiplier(2) .build()) + .build()) + .setPublishing(Publishing.newBuilder() .setCompressBodyThreshold(4 * 1024) .setMaxBodySize(4 * 1024 * 1024) .build()) .build(); protected static final Settings DEFAULT_CONSUMER_SETTINGS = Settings.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(3) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setInitial(Durations.fromSeconds(1)) + .setMax(Durations.fromSeconds(3)) + .setMultiplier(2) + .build()) + .build()) .setSubscription(Subscription.newBuilder() .setFifo(false) - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(16) - .setExponentialBackoff(ExponentialBackoff.newBuilder() - .setInitial(Durations.fromSeconds(5)) - .setMax(Durations.fromMinutes(30)) - .setMultiplier(2) - .build()) - .build()) .setReceiveBatchSize(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) .setLongPollingTimeout(Durations.fromSeconds(30)) .build()) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 070c1e7a4c..effcc98ec5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -344,7 +344,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); - RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy(); + RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getBackoffPolicy(); int maxReconsumeTimes = retryPolicy.getMaxAttempts(); if (request.getDeliveryAttempt() >= maxReconsumeTimes) { ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 0714b5bb23..a900ae6bcc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -209,7 +209,7 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); Settings settings = grpcClientManager.getClientSettings(ctx); - int maxDeliveryAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); + int maxDeliveryAttempts = settings.getBackoffPolicy().getMaxAttempts(); if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { future = this.producer.sendMessageBackThenAckOrg( ctx, @@ -235,7 +235,7 @@ public class ConsumerService extends BaseService { protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, NackMessageRequest request) { - RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getSubscription().getBackoffPolicy(); + RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getBackoffPolicy(); return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, retryPolicy); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index a15e436739..8210b23f28 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -106,6 +106,8 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes .build()); break; } + } catch (Throwable t) { + write(ctx, request, t); } finally { responseStreamObserver.onCompleted(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java index ba50750a16..db9fac9088 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -67,7 +67,7 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi return Collections.emptyList(); } Settings settings = grpcClientManager.getClientSettings(ctx); - int maxAttempts = settings.getSubscription().getBackoffPolicy().getMaxAttempts(); + int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); Resource topic = request.getMessageQueue().getTopic(); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 7639729f38..28f705e75f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -166,9 +166,9 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { }); streamObserver.onNext(TelemetryCommand.newBuilder() .setSettings(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(3).build()).build()) + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(3).build()) + .setSubscription(Subscription.newBuilder().build()) .build()).build()); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index eb3190151e..d24204150c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -78,6 +78,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); Settings clientSettings = Settings.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(16).build()) .setSubscription(Subscription.newBuilder() .setFifo(false) .build()) @@ -135,8 +136,8 @@ public class ConsumerServiceTest extends BaseServiceTest { Settings clientSettings = Settings.newBuilder() .setClientType(ClientType.SIMPLE_CONSUMER) + .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(0).build()) .setSubscription(Subscription.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(0).build()) .setFifo(false) .build()) .build(); @@ -266,10 +267,10 @@ public class ConsumerServiceTest extends BaseServiceTest { private Settings createClientSettings(int maxDeliveryAttempts) { return Settings.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) .setSubscription(Subscription.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(maxDeliveryAttempts) - .build()) .build()) .build(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 41c9d84426..5aa4a24f0e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -698,10 +698,10 @@ public class GrpcBaseTest extends BaseConf { public Settings buildSimpleConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { return Settings.newBuilder() .setClientType(ClientType.SIMPLE_CONSUMER) + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) .setSubscription(Subscription.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(maxDeliveryAttempts) - .build()) .setFifo(fifo) .build()) .build(); @@ -714,10 +714,10 @@ public class GrpcBaseTest extends BaseConf { public Settings buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { return Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(maxDeliveryAttempts) + .build()) .setSubscription(Subscription.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(maxDeliveryAttempts) - .build()) .setFifo(fifo) .build()) .build(); From f36f3c799d15513a305e71ef9f8d5ce683dab61b Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 27 Apr 2022 17:42:05 +0800 Subject: [PATCH 139/338] [ISSUE #3949] v2 support --- .../apache/rocketmq/proxy/ProxyStartup.java | 29 +++- .../common/AbstractStartAndShutdown.java | 28 ++++ .../rocketmq/proxy/common/Shutdown.java | 22 +++ .../apache/rocketmq/proxy/common/Start.java | 22 +++ .../proxy/common/StartAndShutdown.java | 4 +- .../rocketmq/proxy/grpc/GrpcServer.java | 138 +--------------- .../proxy/grpc/GrpcServerBuilder.java | 150 ++++++++++++++++++ 7 files changed, 251 insertions(+), 142 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/Shutdown.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/Start.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java 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 c34d947ab2..9d5a8766f1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -21,6 +21,8 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import java.util.Date; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.BrokerStartup; import org.apache.rocketmq.client.log.ClientLogger; @@ -33,6 +35,8 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; +import org.apache.rocketmq.proxy.grpc.GrpcServerBuilder; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; @@ -59,8 +63,12 @@ public class ProxyStartup { // init thread pool monitor for proxy. initThreadPoolMonitor(); + ThreadPoolExecutor executor = createServerExecutor(); + // create grpcServer - GrpcServer grpcServer = createGrpcServer(); + GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor) + .addService(createServiceProcessor()) + .build(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); // start servers one by one. @@ -85,7 +93,7 @@ public class ProxyStartup { log.info(new Date() + " rmq-proxy startup successfully"); } - private static GrpcServer createGrpcServer() throws Exception { + private static GrpcMessagingProcessor createServiceProcessor() { GrpcForwardService grpcService; String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); if (ProxyMode.isClusterMode(proxyModeStr)) { @@ -109,7 +117,8 @@ public class ProxyStartup { throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); } - return new GrpcServer(grpcService); + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcService); + return new GrpcMessagingProcessor(grpcService); } private static BrokerController createBrokerController() { @@ -117,6 +126,20 @@ public class ProxyStartup { return BrokerStartup.createBrokerController(brokerStartupArgs); } + public static ThreadPoolExecutor createServerExecutor() { + int threadPoolNums = ConfigurationManager.getProxyConfig().getGrpcThreadPoolNums(); + int threadPoolQueueCapacity = ConfigurationManager.getProxyConfig().getGrpcThreadPoolQueueCapacity(); + ThreadPoolExecutor executor = ThreadPoolMonitor.createAndMonitor( + threadPoolNums, + threadPoolNums, + 1, TimeUnit.MINUTES, + "GrpcRequestExecutorThread", + threadPoolQueueCapacity + ); + PROXY_START_AND_SHUTDOWN.appendShutdown(executor::shutdown); + return executor; + } + public static void initThreadPoolMonitor() { ThreadPoolMonitor.init(); ProxyConfig config = ConfigurationManager.getProxyConfig(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java index 35e361fae1..c59f18c4cf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/AbstractStartAndShutdown.java @@ -41,4 +41,32 @@ public abstract class AbstractStartAndShutdown implements StartAndShutdown { startAndShutdownList.get(index).shutdown(); } } + + public void appendStart(Start start) { + this.appendStartAndShutdown(new StartAndShutdown() { + @Override + public void shutdown() throws Exception { + + } + + @Override + public void start() throws Exception { + start.start(); + } + }); + } + + public void appendShutdown(Shutdown shutdown) { + this.appendStartAndShutdown(new StartAndShutdown() { + @Override + public void shutdown() throws Exception { + shutdown.shutdown(); + } + + @Override + public void start() throws Exception { + + } + }); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Shutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Shutdown.java new file mode 100644 index 0000000000..28f4f92f54 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Shutdown.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.proxy.common; + +public interface Shutdown { + void shutdown() throws Exception; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Start.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Start.java new file mode 100644 index 0000000000..3cf74d47d2 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Start.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.proxy.common; + +public interface Start { + void start() throws Exception; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java index ffb2523e97..565e92c25c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/StartAndShutdown.java @@ -17,7 +17,5 @@ package org.apache.rocketmq.proxy.common; -public interface StartAndShutdown { - void start() throws Exception; - void shutdown() throws Exception; +public interface StartAndShutdown extends Start, Shutdown { } 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 78e3770659..d663a88f6d 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 @@ -17,152 +17,22 @@ package org.apache.rocketmq.proxy.grpc; -import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; -import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; -import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup; -import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel; -import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup; -import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; -import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; -import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.grpc.netty.shaded.io.netty.handler.ssl.util.SelfSignedCertificate; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.cert.CertificateException; -import java.util.List; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLException; -import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.common.utils.ServiceProvider; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; -import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; -import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; -import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; public class GrpcServer implements StartAndShutdown { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final io.grpc.Server server; - private final ThreadPoolExecutor executor; - private final GrpcForwardService grpcForwardService; - public GrpcServer(GrpcForwardService grpcForwardService) { - this.grpcForwardService = grpcForwardService; - int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); - NettyServerBuilder serverBuilder = NettyServerBuilder.forPort(port); - - try { - configSslContext(serverBuilder); - } catch (Exception e) { - log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); - throw new RuntimeException("grpc tls set failed: " + e.getMessage()); - } - - // create executor - int threadPoolNums = ConfigurationManager.getProxyConfig().getGrpcThreadPoolNums(); - int threadPoolQueueCapacity = ConfigurationManager.getProxyConfig().getGrpcThreadPoolQueueCapacity(); - this.executor = ThreadPoolMonitor.createAndMonitor( - threadPoolNums, - threadPoolNums, - 1, TimeUnit.MINUTES, - "GrpcRequestExecutorThread", - threadPoolQueueCapacity - ); - - GrpcMessagingProcessor messagingProcessor = createProcessor(); - - // build server - int bossLoopNum = ConfigurationManager.getProxyConfig().getGrpcBossLoopNum(); - int workerLoopNum = ConfigurationManager.getProxyConfig().getGrpcWorkerLoopNum(); - int maxInboundMessageSize = ConfigurationManager.getProxyConfig().getGrpcMaxInboundMessageSize(); - - if (ConfigurationManager.getProxyConfig().isEnableGrpcEpoll()) { - serverBuilder.maxInboundMessageSize(maxInboundMessageSize) - .bossEventLoopGroup(new EpollEventLoopGroup(bossLoopNum)) - .workerEventLoopGroup(new EpollEventLoopGroup(workerLoopNum)) - .channelType(EpollServerSocketChannel.class) - .addService(messagingProcessor) - .executor(this.executor); - } else { - serverBuilder.maxInboundMessageSize(maxInboundMessageSize) - .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) - .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) - .channelType(NioServerSocketChannel.class) - .addService(messagingProcessor) - .executor(this.executor); - } - - configInterceptor(serverBuilder); - this.server = serverBuilder.build(); - - log.info( - "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " - + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", - port, threadPoolNums, threadPoolQueueCapacity, - bossLoopNum, workerLoopNum, maxInboundMessageSize); - } - - protected GrpcMessagingProcessor createProcessor() { - return new GrpcMessagingProcessor(grpcForwardService); - } - - protected void configSslContext(NettyServerBuilder serverBuilder) throws SSLException, CertificateException { - if (null == serverBuilder) { - return; - } - ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - boolean tlsTestModeEnable = proxyConfig.isGrpcTlsTestModeEnable(); - if (tlsTestModeEnable) { - SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - serverBuilder.sslContext(GrpcSslContexts.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .clientAuth(ClientAuth.NONE) - .build()); - return; - } - - String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); - String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); - try (InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); - InputStream serverCertificateStream = new FileInputStream(tlsCertPath)) { - serverBuilder.sslContext(GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .clientAuth(ClientAuth.NONE) - .build()); - log.info("TLS configured OK"); - } catch (IOException e) { - log.error("Failed to load Server key/certificate", e); - } - } - - protected void configInterceptor(NettyServerBuilder serverBuilder) { - // grpc interceptors, including acl, logging etc. - if (ConfigurationManager.getProxyConfig().isEnableACL()) { - List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); - if (accessValidators.isEmpty()) { - throw new IllegalArgumentException("Load AccessValidator failed"); - } - serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); - } - - serverBuilder.intercept(new ContextInterceptor()) - .intercept(new HeaderInterceptor()); + protected GrpcServer(io.grpc.Server server) { + this.server = server; } public void start() throws Exception { - // first to start grpc service. - this.grpcForwardService.start(); - this.server.start(); log.info("grpc server start successfully."); } @@ -170,10 +40,6 @@ public class GrpcServer implements StartAndShutdown { public void shutdown() { try { this.server.shutdown().awaitTermination(30, TimeUnit.SECONDS); - this.executor.shutdown(); - - this.grpcForwardService.shutdown(); - 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 new file mode 100644 index 0000000000..04cac43db3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java @@ -0,0 +1,150 @@ +/* + * 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.grpc; + +import io.grpc.BindableService; +import io.grpc.ServerServiceDefinition; +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel; +import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup; +import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; +import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.SelfSignedCertificate; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.util.List; +import java.util.concurrent.ThreadPoolExecutor; +import javax.net.ssl.SSLException; +import org.apache.rocketmq.acl.AccessValidator; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.utils.ServiceProvider; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; + +public class GrpcServerBuilder { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected NettyServerBuilder serverBuilder; + + public static GrpcServerBuilder newBuilder(ThreadPoolExecutor executor) { + return new GrpcServerBuilder(executor); + } + + public GrpcServerBuilder(ThreadPoolExecutor executor) { + int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); + serverBuilder = NettyServerBuilder.forPort(port); + + try { + configSslContext(serverBuilder); + } catch (Exception e) { + log.error("grpc tls set failed. msg: {}, e:", e.getMessage(), e); + throw new RuntimeException("grpc tls set failed: " + e.getMessage()); + } + + // build server + int bossLoopNum = ConfigurationManager.getProxyConfig().getGrpcBossLoopNum(); + int workerLoopNum = ConfigurationManager.getProxyConfig().getGrpcWorkerLoopNum(); + int maxInboundMessageSize = ConfigurationManager.getProxyConfig().getGrpcMaxInboundMessageSize(); + + if (ConfigurationManager.getProxyConfig().isEnableGrpcEpoll()) { + serverBuilder.maxInboundMessageSize(maxInboundMessageSize) + .bossEventLoopGroup(new EpollEventLoopGroup(bossLoopNum)) + .workerEventLoopGroup(new EpollEventLoopGroup(workerLoopNum)) + .channelType(EpollServerSocketChannel.class) + .executor(executor); + } else { + serverBuilder.maxInboundMessageSize(maxInboundMessageSize) + .bossEventLoopGroup(new NioEventLoopGroup(bossLoopNum)) + .workerEventLoopGroup(new NioEventLoopGroup(workerLoopNum)) + .channelType(NioServerSocketChannel.class) + .executor(executor); + } + + configInterceptor(serverBuilder); + + log.info( + "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", + port, bossLoopNum, workerLoopNum, maxInboundMessageSize); + } + + public GrpcServerBuilder addService(BindableService service) { + this.serverBuilder.addService(service); + return this; + } + + public GrpcServerBuilder addService(ServerServiceDefinition service) { + this.serverBuilder.addService(service); + return this; + } + + public GrpcServer build() { + return new GrpcServer(this.serverBuilder.build()); + } + + protected void configSslContext(NettyServerBuilder serverBuilder) throws SSLException, CertificateException { + if (null == serverBuilder) { + return; + } + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + boolean tlsTestModeEnable = proxyConfig.isGrpcTlsTestModeEnable(); + if (tlsTestModeEnable) { + SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); + serverBuilder.sslContext(GrpcSslContexts.forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .clientAuth(ClientAuth.NONE) + .build()); + return; + } + + String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); + String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); + try (InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); + InputStream serverCertificateStream = new FileInputStream(tlsCertPath)) { + serverBuilder.sslContext(GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .clientAuth(ClientAuth.NONE) + .build()); + log.info("TLS configured OK"); + } catch (IOException e) { + log.error("Failed to load Server key/certificate", e); + } + } + + protected void configInterceptor(NettyServerBuilder serverBuilder) { + // grpc interceptors, including acl, logging etc. + if (ConfigurationManager.getProxyConfig().isEnableACL()) { + List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); + if (accessValidators.isEmpty()) { + throw new IllegalArgumentException("Load AccessValidator failed"); + } + serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); + } + + serverBuilder.intercept(new ContextInterceptor()) + .intercept(new HeaderInterceptor()); + } +} From b47944321e28a56f254576f93a8ef76b4388ed0d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 27 Apr 2022 17:50:10 +0800 Subject: [PATCH 140/338] [ISSUE #3949] Do refector and Fix unit test * Create Channel use Context * Use LocalReceiveMessageResponseStreamWriter to write ReceiveMessageResponse * Change polling time to 1 second to reduce test time --- .../proxy/channel/ChannelManager.java | 36 ++--- .../proxy/channel/InvocationChannel.java | 5 +- .../v1/adapter/channel/GrpcClientChannel.java | 3 +- .../proxy/grpc/v2/adapter/GrpcConverter.java | 23 +++ .../grpc/v2/adapter/ResponseBuilder.java | 3 + .../v2/adapter/channel/GrpcClientChannel.java | 3 +- .../channel/ReceiveMessageChannel.java | 11 +- .../adapter/channel/SendMessageChannel.java | 5 +- .../ReceiveMessageResponseHandler.java | 31 +--- .../grpc/v2/service/LocalGrpcService.java | 86 +++++++---- .../ReceiveMessageResponseStreamObserver.java | 67 ++++++++ .../ReceiveMessageResponseStreamWriter.java | 8 +- .../ReceiveMessageResultFilter.java | 2 +- .../v2/service/cluster/ConsumerService.java | 3 +- ...ultReceiveMessageResponseStreamWriter.java | 52 +------ .../DefaultReceiveMessageResultFilter.java | 27 +--- ...calReceiveMessageResponseStreamWriter.java | 143 ++++++++++++++++++ .../LocalReceiveMessageResultFilter.java | 123 +++++++++++++++ .../grpc/v2/service/LocalGrpcServiceTest.java | 2 +- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 10 +- 20 files changed, 480 insertions(+), 163 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/{cluster => }/ReceiveMessageResponseStreamWriter.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/{cluster => }/ReceiveMessageResultFilter.java (95%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 925d923705..87b6ea2750 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -24,7 +24,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.function.Supplier; +import java.util.function.Function; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; @@ -38,25 +38,25 @@ public class ChannelManager { protected final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); protected final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); - public SimpleChannel createChannel() { - return createChannel(anonymousChannelId()); + public SimpleChannel createChannel(Context ctx) { + return createChannel(ctx, anonymousChannelId(ctx)); } - public SimpleChannel createChannel(String clientId) { - return createChannel(clientId, ChannelManager::createSimpleChannelDirectly, SimpleChannel.class); + public SimpleChannel createChannel(Context ctx, String clientId) { + return createChannel(ctx, clientId, ChannelManager::createSimpleChannelDirectly, SimpleChannel.class); } - public T createChannel(Supplier creator, Class clazz) { - return createChannel(anonymousChannelId(clazz.getName()), creator, clazz); + public T createChannel(Context ctx, Function creator, Class clazz) { + return createChannel(ctx, anonymousChannelId(ctx, clazz.getName()), creator, clazz); } - public T createChannel(String clientId, Supplier creator, Class clazz) { + public T createChannel(Context ctx, String clientId, Function creator, Class clazz) { if (StringUtils.isBlank(clientId)) { log.warn("ClientId is unexpected null or empty"); - return creator.get(); + return creator.apply(ctx); } - clientIdChannelMap.computeIfAbsent(clientId, key -> creator.get()); + clientIdChannelMap.computeIfAbsent(clientId, key -> creator.apply(ctx)); T channel = clazz.cast(clientIdChannelMap.get(clientId)); channel.updateLastAccessTime(); @@ -83,26 +83,22 @@ public class ChannelManager { return clazz.cast(channel); } - private String anonymousChannelId() { - final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + private String anonymousChannelId(Context ctx) { + final String clientHost = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + final String localAddress = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.LOCAL_ADDRESS); return clientHost + "@" + localAddress; } - private String anonymousChannelId(String className) { - final String clientHost = InterceptorConstants.METADATA.get(Context.current()) + private String anonymousChannelId(Context ctx, String className) { + final String clientHost = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(Context.current()) + final String localAddress = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.LOCAL_ADDRESS); return className + "@" + clientHost + "@" + localAddress; } - public static SimpleChannel createSimpleChannelDirectly() { - return createSimpleChannelDirectly(Context.current()); - } - public static SimpleChannel createSimpleChannelDirectly(Context ctx) { final String clientHost = InterceptorConstants.METADATA.get(ctx) .get(InterceptorConstants.REMOTE_ADDRESS); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java index 83dc2428cc..2ae543f254 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.channel; +import io.grpc.Context; import io.netty.channel.ChannelFuture; import java.util.Iterator; import java.util.Map; @@ -30,8 +31,8 @@ public abstract class InvocationChannel extends SimpleChannel implements C protected final ConcurrentMap> inFlightRequestMap; protected final ResponseHandler handler; - public InvocationChannel(ResponseHandler handler) { - super(ChannelManager.createSimpleChannelDirectly()); + public InvocationChannel(Context ctx, ResponseHandler handler) { + super(ChannelManager.createSimpleChannelDirectly(ctx)); this.inFlightRequestMap = new ConcurrentHashMap<>(); this.handler = handler; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java index 99f9ec6601..5792d78cf6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java @@ -74,8 +74,9 @@ public class GrpcClientChannel extends SimpleChannel { TelemetryCommandManager manager ) { GrpcClientChannel channel = channelManager.createChannel( + ctx, buildKey(group, clientId), - () -> new GrpcClientChannel(ctx, group, clientId, manager), + context -> new GrpcClientChannel(context, group, clientId, manager), GrpcClientChannel.class ); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index d8913cfedb..883abf6291 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -237,6 +237,10 @@ public class GrpcConverter { return requestHeader; } + public static AckMessageRequestHeader buildAckMessageRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { + return buildAckMessageRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle); + } + public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); } @@ -305,6 +309,25 @@ public class GrpcConverter { return changeInvisibleTimeRequestHeader; } + public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); + return changeInvisibleTimeRequestHeader; + } + + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(ReceiveMessageRequest request, + ReceiptHandle handle, String messageId, int maxReconsumeTimes) { + return buildConsumerSendMsgBackRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle, messageId, maxReconsumeTimes); + } + public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( NackMessageRequest request, int maxReconsumeTimes) { ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java index 994088bce6..0344f28193 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java @@ -100,6 +100,9 @@ public class ResponseBuilder { case ResponseCode.FLUSH_SLAVE_TIMEOUT: { return Code.SLAVE_PERSISTENCE_TIMEOUT; } + case ResponseCode.POLLING_TIMEOUT: { + return Code.GATEWAY_TIMEOUT; + } default: { return Code.INTERNAL_SERVER_ERROR; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 9a2650239c..7966ab7410 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -72,8 +72,9 @@ public class GrpcClientChannel extends SimpleChannel { TelemetryCommandManager manager ) { GrpcClientChannel channel = channelManager.createChannel( + ctx, buildKey(group, clientId), - () -> new GrpcClientChannel(ctx, group, clientId, manager), + context -> new GrpcClientChannel(context, group, clientId, manager), GrpcClientChannel.class ); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java index 8593b66023..3187df724c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java @@ -18,13 +18,14 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import java.util.Iterator; +import io.grpc.Context; +import java.util.List; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; -public class ReceiveMessageChannel extends InvocationChannel> { - public ReceiveMessageChannel(ReceiveMessageResponseHandler handler) { - super(handler); +public class ReceiveMessageChannel extends InvocationChannel> { + public ReceiveMessageChannel(Context ctx, ReceiveMessageResponseHandler handler) { + super(ctx, handler); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java index 39ce672299..a2b034529d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java @@ -19,11 +19,12 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter.channel; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; +import io.grpc.Context; import org.apache.rocketmq.proxy.channel.InvocationChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; public class SendMessageChannel extends InvocationChannel { - public SendMessageChannel(SendMessageResponseHandler handler) { - super(handler); + public SendMessageChannel(Context context, SendMessageResponseHandler handler) { + super(context, handler); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java index 23ffb5ff6b..ef867235cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java @@ -18,13 +18,10 @@ package org.apache.rocketmq.proxy.grpc.v2.adapter.handler; import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Resource; import com.google.common.base.Stopwatch; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -39,11 +36,10 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.InvocationContext; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; -public class ReceiveMessageResponseHandler implements ResponseHandler> { +public class ReceiveMessageResponseHandler implements ResponseHandler> { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final String brokerName; private final boolean fifo; @@ -55,17 +51,19 @@ public class ReceiveMessageResponseHandler implements ResponseHandler> context) { - CompletableFuture> future = context.getResponse(); + InvocationContext> context) { + CompletableFuture> future = context.getResponse(); long currentTimeInMillis = System.currentTimeMillis(); long popCosts = currentTimeInMillis - context.getTimestamp(); try { Stopwatch stopWatch = Stopwatch.createStarted(); PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) responseCommand.readCustomHeader(); - List responseList = new ArrayList<>(); + List allMessageList = new ArrayList<>(); + ReceiveMessageRequest request = context.getRequest(); if (responseCommand.getCode() == RemotingSysResponseCode.SUCCESS) { + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); List msgFoundList = MessageDecoder.decodes(byteBuffer); @@ -130,29 +128,16 @@ public class ReceiveMessageResponseHandler implements ResponseHandler String.valueOf(responseHeader.getPopTime())); } - - responseList.add(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .build()); - - for (MessageExt messageExt : msgFoundList) { - ReceiveMessageResponse response = ReceiveMessageResponse.newBuilder() - .setMessage(GrpcConverter.buildMessage(messageExt)).build(); - responseList.add(response); - } + allMessageList.addAll(msgFoundList); } long elapsed = stopWatch.stop().elapsed(TimeUnit.MILLISECONDS); log.debug("Translating remoting response to gRPC response costs {}ms. Duration request received: {}", elapsed, popCosts); - future.complete(responseList.iterator()); + future.complete(allMessageList); } catch (Exception e) { log.error("Unexpected exception raised when handle pop remoting command", e); future.completeExceptionally(e); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index effcc98ec5..6f4270a787 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -52,7 +52,6 @@ import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; @@ -64,12 +63,14 @@ import org.apache.rocketmq.broker.client.ConsumerGroupEvent; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.broker.client.ProducerGroupEvent; +import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; @@ -97,16 +98,17 @@ import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; +import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResponseStreamWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResultFilter; import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; +import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.LanguageCode; @@ -125,6 +127,9 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final ClientSettingsService clientSettingsService; private final DelayPolicy delayPolicy; private final LocalWriteQueueSelector localWriteQueueSelector; + private final ReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; + + private volatile ResponseHook receiveMessageHook; public LocalGrpcService(BrokerController brokerController) { this(brokerController, new TelemetryCommandManager()); @@ -151,6 +156,14 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); + this.streamWriterBuilder = (observer, hook) -> new LocalReceiveMessageResponseStreamWriter( + observer, + hook, + channelManager, + brokerController, + new LocalReceiveMessageResultFilter(channelManager, brokerController, grpcClientManager) + ); + this.appendStartAndShutdown(connectorManager); } @@ -235,7 +248,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo command.makeCustomHeaderToNet(); SendMessageResponseHandler handler = new SendMessageResponseHandler(messageId, requestHeader.getSysFlag(), brokerController.getBrokerAddr()); - SendMessageChannel channel = channelManager.createChannel(() -> new SendMessageChannel(handler), SendMessageChannel.class); + SendMessageChannel channel = channelManager.createChannel(ctx, context -> new SendMessageChannel(context, handler), SendMessageChannel.class); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); InvocationContext context @@ -266,16 +279,16 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); // TODO: get fifo config from subscriptionGroupManager boolean fifo = false; + ReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); + ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); + ReceiveMessageChannel channel = channelManager.createChannel(ctx, context -> new ReceiveMessageChannel(context, handler), ReceiveMessageChannel.class); + CompletableFuture> future = new CompletableFuture<>(); + InvocationContext> context + = new InvocationContext<>(request, future); + SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); command.makeCustomHeaderToNet(); - - ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); - ReceiveMessageChannel channel = channelManager.createChannel(() -> new ReceiveMessageChannel(handler), ReceiveMessageChannel.class); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture> future = new CompletableFuture<>(); - InvocationContext> context - = new InvocationContext<>(request, future); channel.registerInvocationContext(command.getOpaque(), context); try { RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(channelHandlerContext, command); @@ -288,26 +301,33 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } - future.thenAccept(r -> ResponseWriter.write(responseObserver, r)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(e)).build() - ); - return null; - }); + future.thenAccept(r -> { + try { + writer.write(ctx, request, PopStatus.FOUND, r); + } finally { + responseObserver.onCompleted(); + } + }).exceptionally(e -> { + writer.write(ctx, request, e); + return null; + }); } @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - Channel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); List ackMessageResultEntryList = new ArrayList<>(); for (AckMessageEntry entry : request.getEntriesList()) { ReceiptHandle receiptHandle = ReceiptHandle.decode(entry.getReceiptHandle()); if (receiptHandle.isExpired()) { - throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); + ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() + .setReceiptHandle(entry.getReceiptHandle()) + .setMessageId(entry.getMessageId()) + .setStatus(ResponseBuilder.buildStatus(Code.RECEIPT_HANDLE_EXPIRED, "expired")) + .build()); + continue; } AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, receiptHandle); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); @@ -340,7 +360,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - Channel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); CompletableFuture future = new CompletableFuture<>(); @@ -385,7 +405,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { - SimpleChannel channel = channelManager.createChannel(); + SimpleChannel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); @@ -409,7 +429,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - Channel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); @@ -436,7 +456,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - public void reportThreadStackTrace(ThreadStackTrace request) { + public void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); @@ -451,13 +471,13 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); runningInfo.setJstack(threadStack); remotingCommand.setBody(runningInfo.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); } } } } - public void reportVerifyMessageResult(VerifyMessageResult request) { + public void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { String nonce = request.getNonce(); TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); if (pollCommandResponseFuture != null) { @@ -470,7 +490,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); remotingCommand.setBody(result.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel()), remotingCommand); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); } } } @@ -479,7 +499,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - Channel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); Settings clientSettings = grpcClientManager.getClientSettings(clientId); @@ -497,7 +517,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { - Channel channel = channelManager.createChannel(); + Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); @@ -546,11 +566,11 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo break; } case THREAD_STACK_TRACE: { - reportThreadStackTrace(request.getThreadStackTrace()); + reportThreadStackTrace(ctx, request.getThreadStackTrace()); break; } case VERIFY_MESSAGE_RESULT: { - reportVerifyMessageResult(request.getVerifyMessageResult()); + reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); break; } default: { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java new file mode 100644 index 0000000000..16a2f29d43 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.service; + +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; + +public class ReceiveMessageResponseStreamObserver implements StreamObserver { + + private final Context context; + private final ReceiveMessageRequest request; + private final ResponseHook receiveMessageHook; + private final StreamObserver observer; + + public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, + ResponseHook receiveMessageHook, + StreamObserver observer) { + this.context = context; + this.request = request; + this.receiveMessageHook = receiveMessageHook; + this.observer = observer; + } + + @Override + public void onNext(ReceiveMessageResponse response) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, response, null); + } + observer.onNext(response); + } + + @Override + public void onError(Throwable throwable) { + if (receiveMessageHook != null) { + receiveMessageHook.beforeResponse(context, request, null, throwable); + } + observer.onError(throwable); + } + + @Override + public void onCompleted() { + observer.onCompleted(); + } + + public boolean isCancelled() { + return ResponseWriter.isCancelled(observer); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java index c1d0625165..8723558b71 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java @@ -14,13 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import io.grpc.Context; import io.grpc.stub.StreamObserver; -import org.apache.rocketmq.client.consumer.PopResult; +import java.util.List; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; public abstract class ReceiveMessageResponseStreamWriter { @@ -41,7 +43,7 @@ public abstract class ReceiveMessageResponseStreamWriter { receiveMessageHook = hook; } - public abstract void write(Context ctx, ReceiveMessageRequest request, PopResult result); + public abstract void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList); public abstract void write(Context ctx, ReceiveMessageRequest request, Throwable throwable); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java index cd291b493b..398dc5d790 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2.service; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index a900ae6bcc..e805708e69 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -52,6 +52,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ConsumerService extends BaseService { @@ -106,7 +107,7 @@ public class ConsumerService extends BaseService { messageQueue.getBrokerName(), requestHeader, requestHeader.getPollTime()) - .thenAccept(result -> writer.write(ctx, request, result)) + .thenAccept(result -> writer.write(ctx, request, result.getPopStatus(), result.getMsgFoundList())) .exceptionally(e -> { writer.write(ctx, request, e); return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index 8210b23f28..9595670646 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -26,10 +26,10 @@ import java.time.Duration; import java.util.Iterator; import java.util.List; import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -40,6 +40,9 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamObserver; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -62,8 +65,7 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes } @Override - public void write(Context ctx, ReceiveMessageRequest request, PopResult result) { - PopStatus status = result.getPopStatus(); + public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( ctx, request, @@ -72,7 +74,7 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes try { switch (status) { case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, result.getMsgFoundList()); + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); if (messageList.isEmpty()) { responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) @@ -159,48 +161,6 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes } } - protected static class ReceiveMessageResponseStreamObserver implements StreamObserver { - - private final Context context; - private final ReceiveMessageRequest request; - private final ResponseHook receiveMessageHook; - private final StreamObserver observer; - - public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, - ResponseHook receiveMessageHook, - StreamObserver observer) { - this.context = context; - this.request = request; - this.receiveMessageHook = receiveMessageHook; - this.observer = observer; - } - - @Override - public void onNext(ReceiveMessageResponse response) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, response, null); - } - observer.onNext(response); - } - - @Override - public void onError(Throwable throwable) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, null, throwable); - } - observer.onError(throwable); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } - - public boolean isCancelled() { - return ResponseWriter.isCancelled(observer); - } - } - public ReceiveMessageResultFilter getReceiveMessageResultFilter() { return receiveMessageResultFilter; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java index db9fac9088..684de08881 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -39,6 +39,7 @@ import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; @@ -98,18 +99,12 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi return; } String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - Resource topic = request.getMessageQueue().getTopic(); - Resource group = request.getGroup(); ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( - topic, - group, + request, handle, messageExt.getMsgId(), maxReconsumeTimes); - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( - topic, - group, - handle); + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); } catch (Throwable t) { @@ -126,19 +121,13 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { CompletableFuture future = new CompletableFuture<>(); - AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - ackMessageRequestHeader.setConsumerGroup(GrpcConverter.wrapResourceWithNamespace(request.getGroup())); - ackMessageRequestHeader.setTopic(messageExt.getTopic()); - ackMessageRequestHeader.setQueueId(handle.getQueueId()); - ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); - ackMessageRequestHeader.setOffset(handle.getOffset()); - future = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageRequestHeader); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..258afd1058 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java @@ -0,0 +1,143 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import io.netty.channel.Channel; +import java.util.Iterator; +import java.util.List; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamObserver; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LocalReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { + private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private final ChannelManager channelManager; + private final BrokerController brokerController; + private final ReceiveMessageResultFilter receiveMessageResultFilter; + + public LocalReceiveMessageResponseStreamWriter( + StreamObserver observer, + ResponseHook hook, + ChannelManager channelManager, + BrokerController brokerController, + ReceiveMessageResultFilter receiveMessageResultFilter) { + super(observer, hook); + this.channelManager = channelManager; + this.brokerController = brokerController; + this.receiveMessageResultFilter = receiveMessageResultFilter; + } + + @Override + public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + try { + switch (status) { + case FOUND: + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); + if (messageList.isEmpty()) { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + } else { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + Iterator messageIterator = messageList.iterator(); + while (messageIterator.hasNext()) { + if (responseStreamObserver.isCancelled()) { + break; + } + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setMessage(messageIterator.next()) + .build()); + } + messageIterator.forEachRemaining(message -> this.changeInvisibleTime(ctx, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle()))); + } + break; + case POLLING_FULL: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .build()); + break; + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + break; + } + } catch (Throwable t) { + write(ctx, request, t); + } finally { + responseStreamObserver.onCompleted(); + } + } + + @Override public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + ResponseWriter.write( + responseStreamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() + ); + } + + private void changeInvisibleTime(Context ctx, ReceiveMessageRequest request, ReceiptHandle handle) { + Channel channel = channelManager.createChannel(ctx); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, handle); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); + command.makeCustomHeaderToNet(); + try { + brokerController.getChangeInvisibleTimeProcessor().processRequest(simpleChannelHandlerContext, command); + } catch (RemotingCommandException e) { + log.error("ChangeInvisibleTime error when write response", e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java new file mode 100644 index 0000000000..62ea8fb78c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java @@ -0,0 +1,123 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Settings; +import io.grpc.Context; +import io.netty.channel.Channel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LocalReceiveMessageResultFilter implements ReceiveMessageResultFilter { + private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + private final ChannelManager channelManager; + private final BrokerController brokerController; + private final GrpcClientManager grpcClientManager; + + public LocalReceiveMessageResultFilter(ChannelManager channelManager, BrokerController brokerController, GrpcClientManager grpcClientManager) { + this.channelManager = channelManager; + this.brokerController = brokerController; + this.grpcClientManager = grpcClientManager; + } + + @Override + public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { + if (messageExtList == null || messageExtList.isEmpty()) { + return Collections.emptyList(); + } + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); + Settings settings = grpcClientManager.getClientSettings(ctx); + int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); + List resMessageList = new ArrayList<>(); + for (MessageExt messageExt : messageExtList) { + if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + ackMessage(ctx, request, messageExt); + continue; + } + if (messageExt.getReconsumeTimes() >= maxAttempts) { + forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); + continue; + } + resMessageList.add(GrpcConverter.buildMessage(messageExt)); + } + return resMessageList; + } + + private void ackMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + Channel channel = channelManager.createChannel(ctx); + AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); + command.makeCustomHeaderToNet(); + try { + brokerController.getAckMessageProcessor().processRequest(new SimpleChannelHandlerContext(channel), command); + } catch (RemotingCommandException e) { + log.error("AckMessage failed in filterMessage", e); + } + } + + private void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempt) { + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + Channel channel = channelManager.createChannel(ctx); + SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempt); + RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, consumerSendMsgBackRequestHeader); + command.makeCustomHeaderToNet(); + RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, command); + if (response.getCode() == ResponseCode.SUCCESS) { + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); + command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, ackMessageRequestHeader); + command.makeCustomHeaderToNet(); + brokerController.getAckMessageProcessor().processRequest(simpleChannelHandlerContext, command); + } + } catch (Exception e) { + log.error("ForwardMessageToDLQ failed in filterMessage", e); + } + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 28f705e75f..a290c62439 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -332,7 +332,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .build()) .build(); ReceiveMessageResponse receiveMessageResponse1 = ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, null)) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build(); Message message = GrpcConverter.buildMessage(messageExt); ReceiveMessageResponse receiveMessageResponse2 = ReceiveMessageResponse.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 5aa4a24f0e..7c4379bacc 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -214,7 +214,7 @@ public class GrpcBaseTest extends BaseConf { // init consumer offset this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - receiveMessage(blockingStub, topic, group); + receiveMessage(blockingStub, topic, group, 1); String messageId = createUniqID(); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); @@ -235,7 +235,7 @@ public class GrpcBaseTest extends BaseConf { // init consumer offset this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - receiveMessage(blockingStub, topic, group); + receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); String messageId = createUniqID(); @@ -313,7 +313,7 @@ public class GrpcBaseTest extends BaseConf { }); telemetryCommandRef.set(null); // init consumer offset - receiveMessage(blockingStub, topic, group); + receiveMessage(blockingStub, topic, group, 1); requestStreamObserver.onNext(TelemetryCommand.newBuilder() .setSettings(buildProducerClientSettings(topic)) @@ -379,7 +379,7 @@ public class GrpcBaseTest extends BaseConf { // init consumer offset this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); - receiveMessage(blockingStub, topic, group); + receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); String messageId = createUniqID(); @@ -436,7 +436,7 @@ public class GrpcBaseTest extends BaseConf { // init consumer offset this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); - receiveMessage(blockingStub, topic, group); + receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); String messageId = createUniqID(); From 6739a051016a083fa23a05cc9a32cf6db8fc14f6 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 27 Apr 2022 17:50:29 +0800 Subject: [PATCH 141/338] [ISSUE #3949] Fix pop ResponseCode.POLLING_TIMEOUT --- .../apache/rocketmq/broker/processor/PopMessageProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b4007d413d..8ac4a6a54f 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 @@ -250,7 +250,7 @@ public class PopMessageProcessor implements NettyRequestProcessor { } if (requestHeader.isTimeoutTooMuch()) { - response.setCode(POLLING_TIMEOUT); + response.setCode(ResponseCode.POLLING_TIMEOUT); response.setRemark(String.format("the broker[%s] poping message is timeout too much", this.brokerController.getBrokerConfig().getBrokerIP1())); return response; From 36347554cff36fab7608e90675198237f71f29fe Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 27 Apr 2022 17:55:53 +0800 Subject: [PATCH 142/338] [ISSUE #3949] Remove unused variables --- .../rocketmq/proxy/grpc/v2/service/LocalGrpcService.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 6f4270a787..5fa9cf55ad 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -54,8 +54,6 @@ import io.netty.channel.Channel; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ClientChannelInfo; @@ -65,7 +63,6 @@ import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.broker.client.ProducerGroupEvent; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.MQVersion; -import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageBatch; @@ -92,7 +89,6 @@ import org.apache.rocketmq.proxy.channel.InvocationContext; import org.apache.rocketmq.proxy.channel.SimpleChannel; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.common.DelayPolicy; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -118,14 +114,11 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final BrokerController brokerController; - private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("LocalGrpcServiceScheduledThread")); private final ChannelManager channelManager; private final TelemetryCommandManager telemetryCommandManager; private final GrpcClientManager grpcClientManager; private final RouteService routeService; private final ClientSettingsService clientSettingsService; - private final DelayPolicy delayPolicy; private final LocalWriteQueueSelector localWriteQueueSelector; private final ReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; @@ -149,7 +142,6 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo this.grpcClientManager = new GrpcClientManager(); this.routeService = new RouteService(connectorManager, grpcClientManager); this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); - this.delayPolicy = DelayPolicy.build(brokerController.getMessageStoreConfig().getMessageDelayLevel()); this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), brokerController.getTopicConfigManager(), connectorManager.getTopicRouteCache()); From f41b7eae6d6d65b25041517fad269da6e1896cdb Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 27 Apr 2022 19:49:57 +0800 Subject: [PATCH 143/338] [ISSUE #3949] Fix ChannelManager --- .../java/org/apache/rocketmq/proxy/channel/ChannelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java index 87b6ea2750..e09180c5b7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java @@ -31,7 +31,7 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v1.adapter.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; public class ChannelManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); From e65ff135b9936caa455bbde3f328345d8f723b9d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 27 Apr 2022 19:49:39 +0800 Subject: [PATCH 144/338] [ISSUE #3949] Remove v1 package --- .../proxy/grpc/v1/GrpcMessagingProcessor.java | 309 -------- .../proxy/grpc/v1/adapter/GrpcConverter.java | 712 ------------------ .../proxy/grpc/v1/adapter/ProxyException.java | 38 - .../grpc/v1/adapter/ResponseBuilder.java | 155 ---- .../proxy/grpc/v1/adapter/V2Converter.java | 68 -- .../v1/adapter/channel/GrpcClientChannel.java | 166 ---- .../grpc/v1/service/ClusterGrpcService.java | 173 ----- .../grpc/v1/service/GrpcForwardService.java | 97 --- 8 files changed, 1718 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java deleted file mode 100644 index 761b247e62..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/GrpcMessagingProcessor.java +++ /dev/null @@ -1,309 +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.proxy.grpc.v1; - -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HealthCheckResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.MessagingServiceGrpc; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.NotifyClientTerminationResponse; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; -import apache.rocketmq.v1.ReportThreadStackTraceRequest; -import apache.rocketmq.v1.ReportThreadStackTraceResponse; -import apache.rocketmq.v1.ResponseCommon; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.grpc.v1.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; - -public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final GrpcForwardService grpcForwardService; - - public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { - this.grpcForwardService = grpcForwardService; - } - - public ResponseCommon convertExceptionToResponseCommon(Throwable t) { - if (t instanceof CompletionException) { - if (t.getCause() instanceof ProxyException) { - ProxyException proxyException = (ProxyException) t.getCause(); - return ResponseBuilder.buildCommon(proxyException.getCode(), proxyException.getMessage()); - } - } - return ResponseBuilder.buildCommon(Code.INTERNAL, "internal error"); - } - - @Override - public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryRoute(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryRouteResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.heartbeat(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - HeartbeatResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void healthCheck(HealthCheckRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.healthCheck(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - HealthCheckResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - SendMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryAssignment(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryAssignmentResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.receiveMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReceiveMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - AckMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void nackMessage(NackMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.nackMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - NackMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, - StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ForwardMessageToDeadLetterQueueResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.endTransaction(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - EndTransactionResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void queryOffset(QueryOffsetRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryOffset(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryOffsetResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void pullMessage(PullMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.pullMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - PullMessageResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void pollCommand(PollCommandRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.pollCommand(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.writeException(responseObserver, e); - return null; - }); - } - - @Override - public void reportThreadStackTrace(ReportThreadStackTraceRequest request, - StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.reportThreadStackTrace(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReportThreadStackTraceResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void reportMessageConsumptionResult(ReportMessageConsumptionResultRequest request, - StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.reportMessageConsumptionResult(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ReportMessageConsumptionResultResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void notifyClientTermination(NotifyClientTerminationRequest request, - StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - NotifyClientTerminationResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } - - @Override - public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, - StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ChangeInvisibleDurationResponse.newBuilder().setCommon(convertExceptionToResponseCommon(e)).build() - ); - return null; - }); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java deleted file mode 100644 index 670ff95749..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/GrpcConverter.java +++ /dev/null @@ -1,712 +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.proxy.grpc.v1.adapter; - -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ConsumeMessageType; -import apache.rocketmq.v1.ConsumeModel; -import apache.rocketmq.v1.ConsumePolicy; -import apache.rocketmq.v1.ConsumerData; -import apache.rocketmq.v1.Digest; -import apache.rocketmq.v1.DigestType; -import apache.rocketmq.v1.Encoding; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.FilterExpression; -import apache.rocketmq.v1.FilterType; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.MessageType; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.ProducerData; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SubscriptionEntry; -import apache.rocketmq.v1.SystemAttribute; -import com.google.common.collect.Maps; -import com.google.protobuf.ByteString; -import com.google.protobuf.Duration; -import com.google.protobuf.Timestamp; -import com.google.protobuf.util.Durations; -import com.google.protobuf.util.Timestamps; -import com.google.rpc.Code; -import io.grpc.Context; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.common.constant.ConsumeInitMode; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.filter.ExpressionType; -import org.apache.rocketmq.common.filter.FilterAPI; -import org.apache.rocketmq.common.message.MessageAccessor; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.NamespaceUtil; -import org.apache.rocketmq.common.protocol.body.CMResult; -import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; -import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.common.sysflag.PullSysFlag; -import org.apache.rocketmq.common.utils.BinaryUtil; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.DelayPolicy; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; - -public class GrpcConverter { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - public static String wrapResourceWithNamespace(Resource resource) { - return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); - } - - public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request) { - SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); - - Message message = request.getMessage(); - SystemAttribute systemAttribute = message.getSystemAttribute(); - - Map property = buildMessageProperty(message); - requestHeader.setProducerGroup(wrapResourceWithNamespace(systemAttribute.getProducerGroup())); - requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); - requestHeader.setDefaultTopic(""); - requestHeader.setDefaultTopicQueueNums(0); - requestHeader.setQueueId(systemAttribute.getPartitionId()); - // sysFlag (body encoding & message type) - int sysFlag = 0; - Encoding bodyEncoding = systemAttribute.getBodyEncoding(); - if (bodyEncoding.equals(Encoding.GZIP)) { - sysFlag |= MessageSysFlag.COMPRESSED_FLAG; - } - // transaction - MessageType messageType = systemAttribute.getMessageType(); - if (messageType.equals(MessageType.TRANSACTION)) { - sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; - } - requestHeader.setSysFlag(sysFlag); - requestHeader.setBornTimestamp(Timestamps.toMillis(systemAttribute.getBornTimestamp())); - requestHeader.setFlag(0); - requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); - requestHeader.setReconsumeTimes(systemAttribute.getDeliveryAttempt()); - - return requestHeader; - } - - public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime) { - Resource group = request.getGroup(); - String groupName = GrpcConverter.wrapResourceWithNamespace(group); - Partition partition = request.getPartition(); - Resource topic = partition.getTopic(); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - int queueId = partition.getId(); - int maxMessageNumbers = request.getBatchSize(); - if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { - log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", - maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); - maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; - } - long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); - long bornTime = Timestamps.toMillis(request.getInitializationTimestamp()); - ConsumePolicy policy = request.getConsumePolicy(); - int initMode = GrpcConverter.buildConsumeInitMode(policy); - - FilterExpression filterExpression = request.getFilterExpression(); - String expression = filterExpression.getExpression(); - String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); - - PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); - requestHeader.setConsumerGroup(groupName); - requestHeader.setTopic(topicName); - requestHeader.setQueueId(queueId); - requestHeader.setMaxMsgNums(maxMessageNumbers); - requestHeader.setInvisibleTime(invisibleTime); - requestHeader.setPollTime(pollTime); - requestHeader.setBornTime(bornTime); - requestHeader.setInitMode(initMode); - requestHeader.setExpType(expressionType); - requestHeader.setExp(expression); - requestHeader.setOrder(request.getFifoFlag()); - - return requestHeader; - } - - public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); - ackMessageRequestHeader.setConsumerGroup(groupName); - ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - ackMessageRequestHeader.setQueueId(handle.getQueueId()); - ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); - ackMessageRequestHeader.setOffset(handle.getOffset()); - return ackMessageRequestHeader; - } - - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, - DelayPolicy delayPolicy) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); -// changeInvisibleTimeRequestHeader.setInvisibleTime( -// delayPolicy.getDelayInterval(ConfigurationManager.getProxyConfig().getRetryDelayLevelDelta() + request.getDeliveryAttempt())); - return changeInvisibleTimeRequestHeader; - } - - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader( - ChangeInvisibleDurationRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); - return changeInvisibleTimeRequestHeader; - } - - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( - ForwardMessageToDeadLetterQueueRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); - consumerSendMsgBackRequestHeader.setGroup(groupName); - consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); - consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); - return consumerSendMsgBackRequestHeader; - } - - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( - NackMessageRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); - consumerSendMsgBackRequestHeader.setGroup(groupName); - consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(request.getMessageId()); - consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(request.getMaxDeliveryAttempts()); - return consumerSendMsgBackRequestHeader; - } - - public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String messageId = request.getMessageId(); - String transactionId = request.getTransactionId(); - TransactionId handle; - try { - handle = TransactionId.decode(transactionId); - } catch (UnknownHostException e) { - throw new ProxyException(Code.INVALID_ARGUMENT, "Parse transaction id failed", e); - } - long transactionStateTableOffset = handle.getTranStateTableOffset(); - long commitLogOffset = handle.getCommitLogOffset(); - boolean fromTransactionCheck = request.getSource() == EndTransactionRequest.Source.SERVER_CHECK; - int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); - - EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); - endTransactionRequestHeader.setProducerGroup(groupName); - endTransactionRequestHeader.setMsgId(messageId); - endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); - endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); - endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); - endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); - endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); - - return endTransactionRequestHeader; - } - - public static PullMessageRequestHeader buildPullMessageRequestHeader(PullMessageRequest request, long pollTimeoutInMillis) { - Partition partition = request.getPartition(); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(partition.getTopic()); - - int queueId = partition.getId(); - int sysFlag = PullSysFlag.buildSysFlag(false, true, true, false, false); - String expression = request.getFilterExpression().getExpression(); - String expressionType = GrpcConverter.buildExpressionType(request.getFilterExpression().getType()); - - PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); - requestHeader.setConsumerGroup(groupName); - requestHeader.setTopic(topicName); - requestHeader.setQueueId(queueId); - requestHeader.setQueueOffset(request.getOffset()); - requestHeader.setMaxMsgNums(request.getBatchSize()); - requestHeader.setSysFlag(sysFlag); - requestHeader.setCommitOffset(0L); - requestHeader.setSuspendTimeoutMillis(pollTimeoutInMillis); - requestHeader.setSubscription(expression); - requestHeader.setSubVersion(0L); - requestHeader.setExpressionType(expressionType); - return requestHeader; - } - - public static Map buildMessageProperty(Message message) { - org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); - // set user properties - Map userProperties = message.getUserAttributeMap(); - for (String key : userProperties.keySet()) { - if (MessageConst.STRING_HASH_SET.contains(key)) { - throw new ProxyException(Code.INVALID_ARGUMENT, "property is used by system: " + key); - } - } - MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); - - // set tag - String tag = message.getSystemAttribute().getTag(); - if (!"".equals(tag)) { - messageWithHeader.setTags(tag); - } - - // set keys - List keysList = message.getSystemAttribute().getKeysList(); - if (keysList.size() > 0) { - messageWithHeader.setKeys(keysList); - } - - // set message id - String messageId = message.getSystemAttribute().getMessageId(); - if ("".equals(messageId)) { - throw new ProxyException(Code.INVALID_ARGUMENT, "message id is empty"); - } - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); - - // set transaction property - MessageType messageType = message.getSystemAttribute().getMessageType(); - if (messageType.equals(MessageType.TRANSACTION)) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); - - Duration transactionResolveDelay = message.getSystemAttribute().getOrphanedTransactionRecoveryPeriod(); - - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, - String.valueOf(Durations.toSeconds(transactionResolveDelay))); - } - // set delay level or deliver timestamp - switch (message.getSystemAttribute().getTimedDeliveryCase()) { - case DELAY_LEVEL: - int delayLevel = message.getSystemAttribute().getDelayLevel(); - if (delayLevel > 0) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(delayLevel)); - } - break; - case DELIVERY_TIMESTAMP: - Timestamp deliveryTimestamp = message.getSystemAttribute().getDeliveryTimestamp(); - String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); - break; - case TIMEDDELIVERY_NOT_SET: - break; - default: - throw new ProxyException(Code.INVALID_ARGUMENT, "unexpected value: " + message.getSystemAttribute().getTimedDeliveryCase()); - } - // set reconsume times - int reconsumeTimes = message.getSystemAttribute().getDeliveryAttempt(); - MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); - // set producer group - Resource producerGroup = message.getSystemAttribute().getProducerGroup(); - String producerGroupName = wrapResourceWithNamespace(producerGroup); - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroupName); - // set message group - String messageGroup = message.getSystemAttribute().getMessageGroup(); - if (!messageGroup.isEmpty()) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); - } - // set trace context - String traceContext = message.getSystemAttribute().getTraceContext(); - if (!traceContext.isEmpty()) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); - } - return messageWithHeader.getProperties(); - } - - public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage) { - String topic = wrapResourceWithNamespace(protoMessage.getTopic()); - - org.apache.rocketmq.common.message.Message message = - new org.apache.rocketmq.common.message.Message(topic, protoMessage.getBody().toByteArray()); - Map messageProperty = buildMessageProperty(protoMessage); - - MessageAccessor.setProperties(message, messageProperty); - return message; - } - - public static String buildExpressionType(FilterType filterType) { - switch (filterType) { - case SQL: - return ExpressionType.SQL92; - case TAG: - default: - return ExpressionType.TAG; - } - } - - public static HeartbeatData buildHeartbeatData(HeartbeatRequest request) { - HeartbeatData heartbeatData = new HeartbeatData(); - heartbeatData.setClientID(request.getClientId()); - Set producerDataSet = new HashSet<>(); - producerDataSet.add(buildProducerData(request.getProducerData())); - heartbeatData.setProducerDataSet(producerDataSet); - Set consumerDataSet = new HashSet<>(); - consumerDataSet.add(buildConsumerData(request.getConsumerData())); - heartbeatData.setConsumerDataSet(consumerDataSet); - return heartbeatData; - } - - public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(ProducerData producerData) { - org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); - buildProducerData.setGroupName(wrapResourceWithNamespace(producerData.getGroup())); - return buildProducerData; - } - - public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(ConsumerData consumerData) { - org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); - buildConsumerData.setGroupName(wrapResourceWithNamespace(consumerData.getGroup())); - buildConsumerData.setConsumeType(buildConsumeType(consumerData.getConsumeType())); - buildConsumerData.setMessageModel(buildMessageModel(consumerData.getConsumeModel())); - buildConsumerData.setConsumeFromWhere(buildConsumeFromWhere(consumerData.getConsumePolicy())); - Set subscriptionDataSet = buildSubscriptionDataSet(consumerData.getSubscriptionsList()); - buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); - return buildConsumerData; - } - - public static ConsumeType buildConsumeType(ConsumeMessageType consumeMessageType) { - switch (consumeMessageType) { - case ACTIVE: - return ConsumeType.CONSUME_ACTIVELY; - case PASSIVE: - default: - return ConsumeType.CONSUME_PASSIVELY; - } - } - - public static MessageModel buildMessageModel(ConsumeModel consumeModel) { - switch (consumeModel) { - case BROADCASTING: - return MessageModel.BROADCASTING; - case CLUSTERING: - default: - return MessageModel.CLUSTERING; - } - } - - public static ConsumeFromWhere buildConsumeFromWhere(ConsumePolicy policy) { - switch (policy) { - case PLAYBACK: - return ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET; - case DISCARD: - return ConsumeFromWhere.CONSUME_FROM_MAX_OFFSET; - case TARGET_TIMESTAMP: - return ConsumeFromWhere.CONSUME_FROM_TIMESTAMP; - case RESUME: - default: - return ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET; - } - } - - public static Set buildSubscriptionDataSet(List subscriptionEntryList) { - Set subscriptionDataSet = new HashSet<>(); - for (SubscriptionEntry sub : subscriptionEntryList) { - String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); - FilterExpression filterExpression = sub.getExpression(); - subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); - } - return subscriptionDataSet; - } - - public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { - String expression = filterExpression.getExpression(); - String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); - try { - return FilterAPI.build(topicName, expression, expressionType); - } catch (Exception e) { - throw new ProxyException(Code.INVALID_ARGUMENT, "expression format is not correct", e); - } - } - - public static int buildConsumeInitMode(ConsumePolicy policy) { - switch (policy) { - case PLAYBACK: - return ConsumeInitMode.MIN; - case RESUME: - default: - return ConsumeInitMode.MAX; - } - } - - public static Message buildMessage(MessageExt messageExt) { - Map userAttributes = buildUserAttributes(messageExt); - SystemAttribute systemAttributes = buildSystemAttributes(messageExt); - Resource topic = buildResource(messageExt.getTopic()); - - return Message.newBuilder() - .setTopic(topic) - .putAllUserAttribute(userAttributes) - .setSystemAttribute(systemAttributes) - .setBody(ByteString.copyFrom(messageExt.getBody())) - .build(); - } - - protected static Map buildUserAttributes(MessageExt messageExt) { - Map userAttributes = new HashMap<>(); - Map properties = messageExt.getProperties(); - - for (Map.Entry property : properties.entrySet()) { - if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { - userAttributes.put(property.getKey(), property.getValue()); - } - } - - return userAttributes; - } - - protected static SystemAttribute buildSystemAttributes(MessageExt messageExt) { - SystemAttribute.Builder systemAttributeBuilder = SystemAttribute.newBuilder(); - - // tag - String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); - if (tag != null) { - systemAttributeBuilder.setTag(tag); - } - - // keys - String keys = messageExt.getKeys(); - if (keys != null) { - String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); - systemAttributeBuilder.addAllKeys(Arrays.asList(keysArray)); - } - - // message_id - String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - if (uniqKey != null) { - systemAttributeBuilder.setMessageId(uniqKey); - } - - // body_digest & body_encoding - String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); - Digest digest = Digest.newBuilder() - .setType(DigestType.MD5) - .setChecksum(md5Result) - .build(); - systemAttributeBuilder.setBodyDigest(digest); - - if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { - systemAttributeBuilder.setBodyEncoding(Encoding.GZIP); - } else { - systemAttributeBuilder.setBodyEncoding(Encoding.IDENTITY); - } - - // message_type - String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); - String isTransValue = "true"; - if (isTransValue.equals(isTrans)) { - systemAttributeBuilder.setMessageType(MessageType.TRANSACTION); - } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { - systemAttributeBuilder.setMessageType(MessageType.DELAY); - } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { - systemAttributeBuilder.setMessageType(MessageType.FIFO); - } else { - systemAttributeBuilder.setMessageType(MessageType.NORMAL); - } - - // born_timestamp (millis) - long bornTimestamp = messageExt.getBornTimestamp(); - systemAttributeBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); - - // born_host - systemAttributeBuilder.setBornHost(messageExt.getBornHostString()); - - // store_timestamp (millis) - long storeTimestamp = messageExt.getStoreTimestamp(); - systemAttributeBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); - - // store_host - SocketAddress storeHost = messageExt.getStoreHost(); - if (storeHost != null) { - systemAttributeBuilder.setStoreHost(storeHost.toString()); - } - - // delay_level - String delayLevel = messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL); - if (delayLevel != null) { - systemAttributeBuilder.setDelayLevel(Integer.parseInt(delayLevel)); - } - - // delivery_timestamp - String deliverMsString; - long deliverMs; - if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { - long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); - deliverMs = System.currentTimeMillis() + delayMs; - systemAttributeBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); - } else { - deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); - if (deliverMsString != null) { - deliverMs = Long.parseLong(deliverMsString); - systemAttributeBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); - } - } - - // sharding key - String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); - if (shardingKey != null) { - systemAttributeBuilder.setMessageGroup(shardingKey); - } - - // receipt_handle && invisible_period - ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); - if (receiptHandle != null) { - systemAttributeBuilder.setReceiptHandle(receiptHandle.encode()); - } - - // partition_id - systemAttributeBuilder.setPartitionId(messageExt.getQueueId()); - - // partition_offset - systemAttributeBuilder.setPartitionOffset(messageExt.getQueueOffset()); - - // delivery_attempt - systemAttributeBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); - - // publisher_group - String producerGroup = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); - if (producerGroup != null) { - systemAttributeBuilder.setProducerGroup(buildResource(producerGroup)); - } - - // trace context - String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); - if (traceContext != null) { - systemAttributeBuilder.setTraceContext(traceContext); - } - - return systemAttributeBuilder.build(); - } - - public static int buildTransactionCommitOrRollback(EndTransactionRequest.TransactionResolution type) { - switch (type) { - case COMMIT: - return MessageSysFlag.TRANSACTION_COMMIT_TYPE; - case ROLLBACK: - return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; - default: - return MessageSysFlag.TRANSACTION_NOT_TYPE; - } - } - - public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult( - ReportMessageConsumptionResultRequest request) { - ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); - switch (request.getStatus().getCode()) { - case Code.OK_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); - break; - } - case Code.INTERNAL_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); - break; - } - case Code.INVALID_ARGUMENT_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); - break; - } - } - consumeMessageDirectlyResult.setRemark("From gRPC client"); - return consumeMessageDirectlyResult; - } - - public static Resource buildResource(String resourceStr) { - return Resource.newBuilder() - .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceStr)) - .setName(NamespaceUtil.withoutNamespace(resourceStr)) - .build(); - } - - public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(NotifyClientTerminationRequest request) { - UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); - header.setClientID(request.getClientId()); - if (request.hasProducerGroup()) { - header.setProducerGroup(wrapResourceWithNamespace(request.getProducerGroup())); - } - if (request.hasConsumerGroup()) { - header.setConsumerGroup(wrapResourceWithNamespace(request.getConsumerGroup())); - } - return header; - } - - public static long buildPollTimeFromContext(Context ctx) { - long timeRemaining = ctx.getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - - return pollTime; - } - -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java deleted file mode 100644 index f452d88c28..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ProxyException.java +++ /dev/null @@ -1,38 +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.proxy.grpc.v1.adapter; - -import com.google.rpc.Code; - -public class ProxyException extends RuntimeException { - - private final Code code; - - public ProxyException(Code code, String errorMessage) { - super(errorMessage); - this.code = code; - } - - public ProxyException(Code code, String message, Throwable cause) { - super(message, cause); - this.code = code; - } - - public Code getCode() { - return code; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java deleted file mode 100644 index aa27f420e6..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/ResponseBuilder.java +++ /dev/null @@ -1,155 +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.proxy.grpc.v1.adapter; - -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.ResponseCommon; -import apache.rocketmq.v1.SendMessageResponse; -import com.google.rpc.Code; -import com.google.rpc.Status; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class ResponseBuilder { - public static ResponseCommon buildCommon(int responseCode, String remark) { - Status status = Status.newBuilder() - .setCode(buildCode(responseCode).getNumber()) - .setMessage(buildMessage(responseCode, remark)) - .build(); - - return ResponseCommon.newBuilder() - .setStatus(status) - .build(); - } - - public static ResponseCommon buildCommon(Code code, String message) { - Status status = Status.newBuilder() - .setCode(code.getNumber()) - .setMessage(message) - .build(); - - return ResponseCommon.newBuilder() - .setStatus(status) - .build(); - } - - public static ResponseCommon buildSuccessCommon() { - Status status = Status.newBuilder() - .setCode(Code.OK.getNumber()) - .setMessage("ok") - .build(); - - return ResponseCommon.newBuilder() - .setStatus(status) - .build(); - } - - public static HeartbeatResponse buildHeartbeatResponse(RemotingCommand command) { - return HeartbeatResponse.newBuilder() - .setCommon(buildCommon(command.getCode(), command.getRemark())) - .build(); - } - - public static SendMessageResponse buildSendMessageResponse(RemotingCommand command) { - SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) command.readCustomHeader(); - String messageId = ""; - String transactionId = ""; - if (responseHeader != null) { - messageId = responseHeader.getMsgId(); - transactionId = responseHeader.getTransactionId(); - } - return SendMessageResponse.newBuilder() - .setCommon(buildCommon(command.getCode(), command.getRemark())) - .setMessageId(StringUtils.defaultString(messageId)) - .setTransactionId(StringUtils.defaultString(transactionId)) - .build(); - } - - public static Code buildCode(int responseCode) { - Code code; - switch (responseCode) { - case ResponseCode.SUCCESS: - case ResponseCode.NO_MESSAGE: { - code = Code.OK; - break; - } - case ResponseCode.SYSTEM_ERROR: { - code = Code.INTERNAL; - break; - } - case ResponseCode.SYSTEM_BUSY: - case ResponseCode.POLLING_FULL: { - code = Code.RESOURCE_EXHAUSTED; - break; - } - case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { - code = Code.UNIMPLEMENTED; - break; - } - case ResponseCode.MESSAGE_ILLEGAL: - case ResponseCode.VERSION_NOT_SUPPORTED: - case ResponseCode.SUBSCRIPTION_PARSE_FAILED: - case ResponseCode.FILTER_DATA_NOT_EXIST: { - code = Code.INVALID_ARGUMENT; - break; - } - case ResponseCode.SERVICE_NOT_AVAILABLE: - case ResponseCode.SLAVE_NOT_AVAILABLE: - case ResponseCode.PULL_RETRY_IMMEDIATELY: - case ResponseCode.PULL_OFFSET_MOVED: - case ResponseCode.SUBSCRIPTION_NOT_LATEST: - case ResponseCode.FILTER_DATA_NOT_LATEST: { - code = Code.UNAVAILABLE; - break; - } - case ResponseCode.NO_PERMISSION: { - code = Code.PERMISSION_DENIED; - break; - } - case ResponseCode.TOPIC_NOT_EXIST: - case ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST: - case ResponseCode.SUBSCRIPTION_NOT_EXIST: - case ResponseCode.PULL_NOT_FOUND: - case ResponseCode.QUERY_NOT_FOUND: - case ResponseCode.CONSUMER_NOT_ONLINE: { - code = Code.NOT_FOUND; - break; - } - case ResponseCode.POLLING_TIMEOUT: - case ResponseCode.FLUSH_DISK_TIMEOUT: - case ResponseCode.FLUSH_SLAVE_TIMEOUT: { - code = Code.DEADLINE_EXCEEDED; - break; - } - default: { - code = Code.UNKNOWN; - } - - } - return code; - } - - public static String buildMessage(int responseCode, String remark) { - if (remark != null) { - return "ResponseCode: " + responseCode + " " + remark; - } - return "ResponseCode: " + responseCode; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java deleted file mode 100644 index 64ce1275db..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/V2Converter.java +++ /dev/null @@ -1,68 +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.proxy.grpc.v1.adapter; - -import apache.rocketmq.v1.ResponseCommon; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Status; - -public class V2Converter { - public static Resource buildResource(apache.rocketmq.v1.Resource resource) { - return Resource.newBuilder() - .setName(resource.getName()) - .setResourceNamespace(resource.getResourceNamespace()) - .build(); - } - - public static HeartbeatRequest buildHeartbeatRequest(apache.rocketmq.v1.HeartbeatRequest request) { - Resource group; - if (request.hasProducerData()) { - group = buildResource(request.getProducerData().getGroup()); - } else if (request.hasConsumerData()) { - group = buildResource(request.getConsumerData().getGroup()); - } else { - throw new IllegalArgumentException("HeartbeatRequest is not valid"); - } - return HeartbeatRequest.newBuilder() - .setGroup(group) - .build(); - } - - public static apache.rocketmq.v1.HeartbeatResponse buildHeartbeatResponse(HeartbeatResponse response) { - return apache.rocketmq.v1.HeartbeatResponse.newBuilder() - .setCommon(ResponseCommon.newBuilder() - .setStatus(buildStatus(response.getStatus())) - .build()) - .build(); - } - - public static com.google.rpc.Status buildStatus(Status status) { - return com.google.rpc.Status.newBuilder() - .setCode(buildCodeValue(status.getCode())) - .setMessage(status.getMessage()) - .build(); - } - - public static int buildCodeValue(Code code) { - // TODO: complete code mapping - return com.google.rpc.Code.OK_VALUE; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java deleted file mode 100644 index 5792d78cf6..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/adapter/channel/GrpcClientChannel.java +++ /dev/null @@ -1,166 +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.proxy.grpc.v1.adapter.channel; - -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PrintThreadStackTraceCommand; -import apache.rocketmq.v1.RecoverOrphanedTransactionCommand; -import io.grpc.Context; -import io.netty.channel.ChannelFuture; -import java.nio.ByteBuffer; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; -import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.grpc.v1.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class GrpcClientChannel extends SimpleChannel { - private final AtomicReference> pollCommandResponseFutureRef = new AtomicReference<>(); - - private final String group; - private final String clientId; - private final TelemetryCommandManager manager; - - private GrpcClientChannel(String group, String clientId, TelemetryCommandManager manager) { - this(Context.current(), group, clientId, manager); - } - - private GrpcClientChannel(Context ctx, String group, String clientId, TelemetryCommandManager manager) { - super(ChannelManager.createSimpleChannelDirectly(ctx)); - this.group = group; - this.clientId = clientId; - this.manager = manager; - } - - public void setClientObserver(CompletableFuture future) { - this.pollCommandResponseFutureRef.set(future); - } - - public static GrpcClientChannel create( - ChannelManager channelManager, - String group, - String clientId, - TelemetryCommandManager manager - ) { - return create(Context.current(), channelManager, group, clientId, manager); - } - - public static GrpcClientChannel create( - Context ctx, - ChannelManager channelManager, - String group, - String clientId, - TelemetryCommandManager manager - ) { - GrpcClientChannel channel = channelManager.createChannel( - ctx, - buildKey(group, clientId), - context -> new GrpcClientChannel(context, group, clientId, manager), - GrpcClientChannel.class - ); - - channelManager.addGroupClientId(group, clientId); - return channel; - } - - public static GrpcClientChannel getChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannel.class); - } - - public static GrpcClientChannel removeChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannel.class); - } - - private static String buildKey(String group, String clientId) { - return group + "@" + clientId; - } - - @Override - public boolean isWritable() { - if (this.pollCommandResponseFutureRef.get() == null) { - return false; - } - return !this.pollCommandResponseFutureRef.get().isDone(); - } - - /** - * Write response to corresponding remote client - * - * @param msg Target write object, {@link RemotingCommand} or {@link PollCommandResponse} - * @return Always success {@link ChannelFuture} - *

- * Case {@link RequestCode#CHECK_TRANSACTION_STATE} - * @see org.apache.rocketmq.broker.client.net.Broker2Client#checkProducerTransactionState - */ - @Override - public ChannelFuture writeAndFlush(Object msg) { - CompletableFuture future = pollCommandResponseFutureRef.get(); - if (msg instanceof RemotingCommand) { - RemotingCommand command = (RemotingCommand) msg; - try { - switch (command.getCode()) { - case RequestCode.CHECK_TRANSACTION_STATE: { - final CheckTransactionStateRequestHeader requestHeader = command.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); - MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); - future.complete(PollCommandResponse.newBuilder() - .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() - .setTransactionId(requestHeader.getTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) - .build()) - .build()); - break; - } - case RequestCode.GET_CONSUMER_RUNNING_INFO: { - final GetConsumerRunningInfoRequestHeader requestHeader = command.decodeCommandCustomHeader(GetConsumerRunningInfoRequestHeader.class); - if (!requestHeader.isJstackEnable()) { - break; - } - String commandId = manager.putCommand(command.getOpaque()); - future.complete(PollCommandResponse.newBuilder() - .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() - .setCommandId(commandId) - .build()) - .build()); - break; - } - } - } catch (Exception ignore) { - - } - } - if (msg instanceof PollCommandResponse) { - PollCommandResponse response = (PollCommandResponse) msg; - future.complete(response); - } - return super.writeAndFlush(msg); - } - - public String getGroup() { - return group; - } - - public String getClientId() { - return clientId; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java deleted file mode 100644 index a0746f8a79..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/ClusterGrpcService.java +++ /dev/null @@ -1,173 +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.proxy.grpc.v1.service; - -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HealthCheckResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.NotifyClientTerminationResponse; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; -import apache.rocketmq.v1.ReportThreadStackTraceRequest; -import apache.rocketmq.v1.ReportThreadStackTraceResponse; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import com.google.rpc.Code; -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.grpc.v1.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v1.adapter.V2Converter; - -public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - private final org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService clusterGrpcService; - - public ClusterGrpcService() { - this.clusterGrpcService = new org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService(); - - this.appendStartAndShutdown(clusterGrpcService); - } - - @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return null; - } - - @Override - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - return clusterGrpcService.heartbeat(ctx, V2Converter.buildHeartbeatRequest(request)) - .thenApply(V2Converter::buildHeartbeatResponse); - } - - @Override - public CompletableFuture healthCheck(Context ctx, HealthCheckRequest request) { - return CompletableFuture.completedFuture( - HealthCheckResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build() - ); - } - - @Override - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - return null; - } - - @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return null; - } - - @Override - public CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request) { - return null; - } - - @Override - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return null; - } - - @Override - public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - return null; - } - - @Override - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { - return null; - } - - @Override - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - return null; - } - - @Override - public CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request) { - return null; - } - - @Override - public CompletableFuture pullMessage(Context ctx, PullMessageRequest request) { - return null; - } - - @Override - public CompletableFuture pollCommand(Context ctx, PollCommandRequest request) { - return null; - } - - @Override - public CompletableFuture reportThreadStackTrace(Context ctx, - ReportThreadStackTraceRequest request) { - return null; - } - - @Override - public CompletableFuture reportMessageConsumptionResult(Context ctx, - ReportMessageConsumptionResultRequest request) { - return null; - } - - @Override - public CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request) { - return CompletableFuture.completedFuture( - NotifyClientTerminationResponse.newBuilder() - .setCommon(ResponseBuilder.buildCommon(Code.OK, Code.OK.name())) - .build() - ); - } - - @Override - public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { - return null; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java deleted file mode 100644 index d279efba95..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v1/service/GrpcForwardService.java +++ /dev/null @@ -1,97 +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.proxy.grpc.v1.service; - -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.ChangeInvisibleDurationRequest; -import apache.rocketmq.v1.ChangeInvisibleDurationResponse; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.EndTransactionResponse; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v1.HealthCheckRequest; -import apache.rocketmq.v1.HealthCheckResponse; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.HeartbeatResponse; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.NackMessageResponse; -import apache.rocketmq.v1.NotifyClientTerminationRequest; -import apache.rocketmq.v1.NotifyClientTerminationResponse; -import apache.rocketmq.v1.PollCommandRequest; -import apache.rocketmq.v1.PollCommandResponse; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.PullMessageResponse; -import apache.rocketmq.v1.QueryAssignmentRequest; -import apache.rocketmq.v1.QueryAssignmentResponse; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.QueryOffsetResponse; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.ReportMessageConsumptionResultRequest; -import apache.rocketmq.v1.ReportMessageConsumptionResultResponse; -import apache.rocketmq.v1.ReportThreadStackTraceRequest; -import apache.rocketmq.v1.ReportThreadStackTraceResponse; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import io.grpc.Context; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import java.util.concurrent.CompletableFuture; - -public interface GrpcForwardService extends StartAndShutdown { - CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); - - CompletableFuture heartbeat(Context ctx, HeartbeatRequest request); - - CompletableFuture healthCheck(Context ctx, HealthCheckRequest request); - - CompletableFuture sendMessage(Context ctx, SendMessageRequest request); - - CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - - CompletableFuture receiveMessage(Context ctx, ReceiveMessageRequest request); - - CompletableFuture ackMessage(Context ctx, AckMessageRequest request); - - CompletableFuture nackMessage(Context ctx, NackMessageRequest request); - - CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request); - - CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); - - CompletableFuture queryOffset(Context ctx, QueryOffsetRequest request); - - CompletableFuture pullMessage(Context ctx, PullMessageRequest request); - - CompletableFuture pollCommand(Context ctx, PollCommandRequest request); - - CompletableFuture reportThreadStackTrace(Context ctx, - ReportThreadStackTraceRequest request); - - CompletableFuture reportMessageConsumptionResult(Context ctx, - ReportMessageConsumptionResultRequest request); - - CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request); - - CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request); -} From 24467eabc67f0f56c5bad637673d1616c38c1197 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 28 Apr 2022 14:54:49 +0800 Subject: [PATCH 145/338] [ISSUE #3949] Fetch Endpoints from request --- .../proxy/grpc/v2/service/cluster/RouteService.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java index e8c206b609..b238335f2b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java @@ -26,7 +26,6 @@ import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.Settings; import io.grpc.Context; import java.util.ArrayList; import java.util.List; @@ -63,12 +62,12 @@ public class RouteService extends AbstractRouteService { List queueDataList = topicRouteData.getQueueDatas(); List messageQueueList = new ArrayList<>(); - Settings clientSettings = grpcClientManager.getClientSettings(ctx); - Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); + Endpoints endpoints = request.getEndpoints(); + Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, endpoints); if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { future.complete(QueryRouteResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - clientSettings.getAccessPoint() + " is invalidate")) + endpoints + " is invalidate")) .build()); return future; } @@ -110,12 +109,12 @@ public class RouteService extends AbstractRouteService { try { List assignments = new ArrayList<>(); List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); - Settings clientSettings = grpcClientManager.getClientSettings(ctx); - Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, clientSettings.getAccessPoint()); + Endpoints endpoints = request.getEndpoints(); + Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, endpoints); if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { future.complete(QueryAssignmentResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - clientSettings.getAccessPoint() + " is invalidate")) + endpoints + " is invalidate")) .build()); return future; } From 9f090e245025376fc10cbe2879e2241ade2307d1 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 28 Apr 2022 15:59:17 +0800 Subject: [PATCH 146/338] [ISSUE #3949] v2 support --- .../rocketmq/proxy/connector/ForwardWriteConsumer.java | 9 ++++++--- .../proxy/connector/factory/ForwardClientManager.java | 9 +++++---- .../proxy/grpc/v2/service/ClusterGrpcService.java | 4 ++-- .../proxy/grpc/v2/service/cluster/ConsumerService.java | 6 +++--- .../DefaultReceiveMessageResponseStreamWriter.java | 1 + .../cluster/DefaultReceiveMessageResultFilter.java | 2 +- .../grpc/v2/service/cluster/ConsumerServiceTest.java | 6 +++--- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java index 6be934cbb6..5404c77a96 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java @@ -48,13 +48,14 @@ public class ForwardWriteConsumer extends AbstractForwardClient { return clientFactory.getMQClient(name, threadCount); } - public CompletableFuture ackMessage(Context ctx, String address, AckMessageRequestHeader requestHeader) { - return this.ackMessage(ctx, address, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + public CompletableFuture ackMessage(Context ctx, String address, String messageId, AckMessageRequestHeader requestHeader) { + return this.ackMessage(ctx, address, messageId, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture ackMessage( Context ctx, String address, + String messageId, AckMessageRequestHeader requestHeader, long timeoutMillis ) { @@ -65,15 +66,17 @@ public class ForwardWriteConsumer extends AbstractForwardClient { Context ctx, String address, String brokerName, + String messageId, ChangeInvisibleTimeRequestHeader requestHeader ) { - return this.changeInvisibleTimeAsync(ctx, address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); + return this.changeInvisibleTimeAsync(ctx, address, brokerName, messageId, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); } public CompletableFuture changeInvisibleTimeAsync( Context ctx, String address, String brokerName, + String messageId, ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis ) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java index 28bd923381..af75583b0c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java @@ -39,6 +39,11 @@ public class ForwardClientManager implements StartAndShutdown { this.init(transactionStateChecker); } + public ForwardClientManager(TransactionStateChecker transactionStateChecker, RPCHook rpcHook) { + this.rpcHook = rpcHook; + this.init(transactionStateChecker); + } + protected void init(TransactionStateChecker transactionStateChecker) { System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); @@ -68,10 +73,6 @@ public class ForwardClientManager implements StartAndShutdown { return transactionalProducerFactory.getOne(instanceName, bootstrapWorkerThreads); } - public void setRpcHook(RPCHook rpcHook) { - this.rpcHook = rpcHook; - } - @Override public void start() throws Exception { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 40258fbb83..6ebc350747 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -168,7 +168,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc return clientService.telemetry(ctx, responseObserver); } - private class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { + protected class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { @Override public void start() throws Exception { @@ -180,7 +180,7 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc } } - private class GrpcTransactionStateChecker implements TransactionStateChecker { + protected class GrpcTransactionStateChecker implements TransactionStateChecker { @Override public void checkTransactionState(TransactionStateCheckRequest checkData) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index e805708e69..c5519dccee 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -169,7 +169,7 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); - CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, requestHeader); + CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageEntry.getMessageId(), requestHeader); ackResultFuture .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) .exceptionally(throwable -> { @@ -220,7 +220,7 @@ public class ConsumerService extends BaseService { ).thenApply(result -> convertToNackMessageResponse(ctx, request, result)); } else { ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), requestHeader) + future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), request.getMessageId(), requestHeader) .thenApply(result -> convertToNackMessageResponse(ctx, request, result)); } } catch (Throwable t) { @@ -278,7 +278,7 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), requestHeader) + future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), "", requestHeader) .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index 9595670646..0c8f50547a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -148,6 +148,7 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes ctx, brokerAddr, handle.getBrokerName(), + message.getSystemProperties().getMessageId(), changeInvisibleTimeRequestHeader ).whenComplete((ackResult, t) -> { if (t != null) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java index 684de08881..b15951eb74 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -128,7 +128,7 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); try { String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - future = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageRequestHeader); + future = this.writeConsumer.ackMessage(ctx, brokerAddr, messageExt.getMsgId(), ackMessageRequestHeader); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index d24204150c..0911a9956a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -93,7 +93,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - when(writeConsumerClient.ackMessage(any(), anyString(), any())) + when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())) .thenReturn(CompletableFuture.completedFuture(new AckResult())); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); @@ -190,7 +190,7 @@ public class ConsumerServiceTest extends BaseServiceTest { when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.ackMessage(any(), anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); + when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); AckMessageResponse response = consumerService.ackMessage(Context.current(), AckMessageRequest.newBuilder() .setTopic(Resource.newBuilder() @@ -241,7 +241,7 @@ public class ConsumerServiceTest extends BaseServiceTest { ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), headerArgumentCaptor.capture())) + when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), anyString(), headerArgumentCaptor.capture())) .thenReturn(CompletableFuture.completedFuture(ackResult)); when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); From 8dc4d516d7731248cea3cebf89fecf14930890f4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 28 Apr 2022 16:09:36 +0800 Subject: [PATCH 147/338] [ISSUE #3949] v2 support --- .../v2/service/cluster/ConsumerService.java | 3 +- .../v2/service/cluster/RouteServiceTest.java | 19 +- .../test/grpc/v1/ClusterGrpcTest.java | 123 ----------- .../rocketmq/test/grpc/v1/GrpcBaseTest.java | 207 ------------------ .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 20 +- 5 files changed, 27 insertions(+), 345 deletions(-) delete mode 100644 test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java delete mode 100644 test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index c5519dccee..8df9fd14f7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -278,7 +278,8 @@ public class ConsumerService extends BaseService { String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), "", requestHeader) + future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), + request.getMessageId(), requestHeader) .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java index b013eb5965..65c0889a67 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -61,16 +61,19 @@ public class RouteServiceTest extends BaseServiceTest { .setResourceNamespace(NAMESPACE) .build(); - private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) + private static final Endpoints WITH_HOST_ENDPOINT = Endpoints.newBuilder() + .addAddresses(Address.newBuilder() + .setPort(80) + .setHost("host") .build()) + .setScheme(AddressScheme.DOMAIN_NAME) .build(); + private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() + .setAccessPoint(WITH_HOST_ENDPOINT) + .build(); + + private static final Settings INVALID_HOST_SETTINGS = Settings.newBuilder() .setAccessPoint(Endpoints.getDefaultInstance()) .build(); @@ -185,6 +188,7 @@ public class RouteServiceTest extends BaseServiceTest { .setTopic(Resource.newBuilder() .setName("topic") .build()) + .setEndpoints(WITH_HOST_ENDPOINT) .build()); QueryRouteResponse response = future.get(); @@ -228,6 +232,7 @@ public class RouteServiceTest extends BaseServiceTest { when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() + .setEndpoints(WITH_HOST_ENDPOINT) .setTopic(Resource.newBuilder() .setName("topic") .build()) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java deleted file mode 100644 index 5d40e39e29..0000000000 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v1/ClusterGrpcTest.java +++ /dev/null @@ -1,123 +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.test.grpc.v1; - -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.Address; -import apache.rocketmq.v1.AddressScheme; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.MessagingServiceGrpc; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.SendMessageResponse; -import com.google.common.base.Stopwatch; -import io.grpc.Channel; -import java.net.URL; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.v1.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.v1.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.v1.service.GrpcForwardService; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; -import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; -import static org.junit.Assert.assertTrue; - -public class ClusterGrpcTest extends GrpcBaseTest { - - private final int PORT = 8083; - private GrpcForwardService grpcForwardService; - private MessagingServiceGrpc.MessagingServiceBlockingStub blockingStub; - - @Before - public void setUp() throws Exception { - String mockProxyHome = "/mock/rmq/proxy/home"; - URL mockProxyHomeURL = getClass().getClassLoader().getResource("rmq-proxy-home"); - if (mockProxyHomeURL != null) { - mockProxyHome = mockProxyHomeURL.toURI().getPath(); - } - System.setProperty(RMQ_PROXY_HOME, mockProxyHome); - ConfigurationManager.initEnv(); - ConfigurationManager.intConfig(); - ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); - ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); - grpcForwardService = new ClusterGrpcService(); - grpcForwardService.start(); - GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); - Channel channel = setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); - blockingStub = MessagingServiceGrpc.newBlockingStub(channel); - } - - @After - public void tearDown() throws Exception { - grpcForwardService.shutdown(); - shutdown(); - } - - @Test - public void testQueryRoute() { - String topic = initTopic(); - QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic, Endpoints.newBuilder() - .setScheme(AddressScheme.IPv4) - .addAddresses(Address.newBuilder() - .setHost("127.0.0.1") - .setPort(PORT) - .build()) - .build())); - assertQueryRoute(response, brokerControllerList.size()); - } - - @Test - public void testSendReceiveMessage() { - String group = "group"; - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(broker1Name, messageId)); - assertSendMessage(sendResponse, messageId); - - ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(3, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); - assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); - assertAck(ackMessageResponse); - } - - @Test - public void testSendReceiveDelayMessage() { - String group = "group"; - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendDelayMessageRequest(broker1Name, messageId, 2)); - assertSendMessage(sendResponse, messageId); - - Stopwatch stopwatch = Stopwatch.createStarted(); - ReceiveMessageResponse receiveResponse = blockingStub.withDeadlineAfter(10, TimeUnit.SECONDS) - .receiveMessage(buildReceiveMessageRequest(group, broker1Name)); - long rcvTime = stopwatch.elapsed(TimeUnit.SECONDS); - assertTrue(Math.abs(rcvTime - 5) < 2); - - assertReceiveMessage(receiveResponse, messageId); - String receiptHandle = receiveResponse.getMessages(0).getSystemAttribute().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(group, broker1Name, receiptHandle)); - assertAck(ackMessageResponse); - } - - -} diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java deleted file mode 100644 index 5494f5405d..0000000000 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v1/GrpcBaseTest.java +++ /dev/null @@ -1,207 +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.test.grpc.v1; - -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.AckMessageResponse; -import apache.rocketmq.v1.Endpoints; -import apache.rocketmq.v1.Message; -import apache.rocketmq.v1.Partition; -import apache.rocketmq.v1.QueryRouteRequest; -import apache.rocketmq.v1.QueryRouteResponse; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.ReceiveMessageResponse; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; -import apache.rocketmq.v1.SendMessageResponse; -import apache.rocketmq.v1.SystemAttribute; -import com.google.protobuf.ByteString; -import com.google.protobuf.Duration; -import com.google.protobuf.Timestamp; -import com.google.rpc.Code; -import io.grpc.Channel; -import io.grpc.ServerInterceptors; -import io.grpc.ServerServiceDefinition; -import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; -import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; -import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; -import io.grpc.testing.GrpcCleanupRule; -import io.netty.handler.ssl.ApplicationProtocolNames; -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import io.netty.handler.ssl.util.SelfSignedCertificate; -import java.io.IOException; -import java.security.cert.CertificateException; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; -import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; -import org.apache.rocketmq.test.base.BaseConf; -import org.junit.Rule; - -import static org.assertj.core.api.Assertions.assertThat; - -public class GrpcBaseTest extends BaseConf { - /** - * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. - */ - @Rule - public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - - private static final int defaultQueueNums = 8; - - protected Channel setUpServer(apache.rocketmq.v1.MessagingServiceGrpc.MessagingServiceImplBase serverImpl, - int port, boolean enableInterceptor) throws IOException, CertificateException { - SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); - ServerServiceDefinition serviceDefinition = ServerInterceptors.intercept(serverImpl); - if (enableInterceptor) { - serviceDefinition = ServerInterceptors.intercept(serverImpl, new ContextInterceptor(), new HeaderInterceptor()); - } - // Create a server, add service, start, and register for automatic graceful shutdown. - grpcCleanup.register(NettyServerBuilder.forPort(port) - .directExecutor() - .addService(serviceDefinition) - .useTransportSecurity(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) - .build() - .start()); - // Create a client channel and register for automatic graceful shutdown. - return grpcCleanup.register(NettyChannelBuilder.forAddress("127.0.0.1", port) - .directExecutor() - .sslContext(SslContextBuilder - .forClient() - .sslProvider(SslProvider.OPENSSL) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .applicationProtocolConfig(new ApplicationProtocolConfig( - ApplicationProtocolConfig.Protocol.ALPN, - ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, - ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, - ApplicationProtocolNames.HTTP_2)) - .build() - ) - .build()); - } - - public QueryRouteRequest buildQueryRouteRequest(String topic) { - return buildQueryRouteRequest(topic, Endpoints.getDefaultInstance()); - } - - public QueryRouteRequest buildQueryRouteRequest(String topic, Endpoints endpoints) { - return QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setEndpoints(endpoints) - .build(); - } - - public SendMessageRequest buildSendMessageRequest(String topic, String messageId) { - return SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId(messageId) - .setPartitionId(0) - .build()) - .setBody(ByteString.copyFromUtf8("123")) - .build()) - .build(); - } - - public SendMessageRequest buildSendDelayMessageRequest(String topic, String messageId, int delayLevel) { -// Message message; -// message.getSystemAttribute().getTimedDeliveryCase(); - return SendMessageRequest.newBuilder() - .setMessage(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setSystemAttribute(SystemAttribute.newBuilder() - .setMessageId(messageId) - .setPartitionId(0) - .setDelayLevel(delayLevel) - .build()) - .setBody(ByteString.copyFromUtf8("123")) - .build()) - .build(); - } - - public ReceiveMessageRequest buildReceiveMessageRequest(String group, String topic) { - return ReceiveMessageRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName(group) - .build()) - .setPartition(Partition.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setId(0) - .build()) - .setBatchSize(16) - .setInvisibleDuration(Duration.newBuilder() - .setSeconds(3) - .build()) - .setInitializationTimestamp(Timestamp.newBuilder() - .setSeconds(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())) - .build()) - .build(); - } - - public AckMessageRequest buildAckMessageRequest(String group, String topic, String receiptHandle) { - return AckMessageRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName(group) - .build()) - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setReceiptHandle(receiptHandle) - .build(); - } - - public void assertQueryRoute(QueryRouteResponse response, int brokerSize) { - assertThat(response.getCommon().getStatus().getCode()).isEqualTo(Code.OK_VALUE); - assertThat(response.getPartitionsList().size()).isEqualTo(brokerSize * defaultQueueNums); - assertThat(response.getPartitions(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); - } - - public void assertSendMessage(SendMessageResponse response, String messageId) { - assertThat(response.getCommon() - .getStatus() - .getCode()).isEqualTo(Code.OK.getNumber()); - assertThat(response.getMessageId()).isEqualTo(messageId); - } - - public void assertReceiveMessage(ReceiveMessageResponse response, String messageId) { - assertThat(response.getCommon() - .getStatus() - .getCode()).isEqualTo(Code.OK.getNumber()); - assertThat(response.getMessagesCount()).isEqualTo(1); - assertThat(response.getMessages(0) - .getSystemAttribute() - .getMessageId()).isEqualTo(messageId); - } - - public void assertAck(AckMessageResponse response) { - assertThat(response.getCommon() - .getStatus() - .getCode()).isEqualTo(Code.OK_VALUE); - } -} \ No newline at end of file diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index 7c4379bacc..b008ead8d0 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -500,6 +500,7 @@ public class GrpcBaseTest extends BaseConf { public QueryRouteRequest buildQueryRouteRequest(String topic) { return QueryRouteRequest.newBuilder() + .setEndpoints(buildEndpoints(PORT)) .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -508,6 +509,7 @@ public class GrpcBaseTest extends BaseConf { public QueryAssignmentRequest buildQueryAssignmentRequest(String topic, String group) { return QueryAssignmentRequest.newBuilder() + .setEndpoints(buildEndpoints(PORT)) .setTopic(Resource.newBuilder().setName(topic).build()) .setGroup(Resource.newBuilder().setName(group).build()) .build(); @@ -683,15 +685,19 @@ public class GrpcBaseTest extends BaseConf { assertThat(response.getReceiptHandle()).isNotEqualTo(prevHandle); } + public Endpoints buildEndpoints(int port) { + return Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder() + .setHost("127.0.0.1") + .setPort(port) + .build()) + .build(); + } + public Settings buildAccessPointClientSettings(int port) { return Settings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .setScheme(AddressScheme.IPv4) - .addAddresses(Address.newBuilder() - .setHost("127.0.0.1") - .setPort(port) - .build()) - .build()) + .setAccessPoint(buildEndpoints(port)) .build(); } From 24742fbba016774ca9a9afb9b1004d8e957f341c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 28 Apr 2022 16:12:11 +0800 Subject: [PATCH 148/338] [ISSUE #3949] v2 support --- acl/pom.xml | 2 -- pom.xml | 1 - proxy/pom.xml | 2 -- test/pom.xml | 2 -- 4 files changed, 7 deletions(-) diff --git a/acl/pom.xml b/acl/pom.xml index ce9c9d6411..c80cc24b5c 100644 --- a/acl/pom.xml +++ b/acl/pom.xml @@ -22,8 +22,6 @@ ${project.groupId} rocketmq-proto - 2.0.0-SNAPSHOT - compatible ${project.groupId} diff --git a/pom.xml b/pom.xml index 2f14a7bb45..f32f831896 100644 --- a/pom.xml +++ b/pom.xml @@ -455,7 +455,6 @@ ${project.groupId} rocketmq-proto 2.0.0-SNAPSHOT - compatible ${project.groupId} diff --git a/proxy/pom.xml b/proxy/pom.xml index ead6de6a5b..944de82261 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -39,8 +39,6 @@ org.apache.rocketmq rocketmq-proto - 2.0.0-SNAPSHOT - compatible org.apache.rocketmq diff --git a/test/pom.xml b/test/pom.xml index 823d3f75f1..f0d292a15b 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -35,8 +35,6 @@ ${project.groupId} rocketmq-proto - 2.0.0-SNAPSHOT - compatible com.google.protobuf From 4cc05ebf119653cd0c29aa3116ede62c2fa58971 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 28 Apr 2022 16:42:28 +0800 Subject: [PATCH 149/338] [ISSUE #3949] Remove v1 package --- .../acl/plain/PlainAccessValidator.java | 59 ++++++++----------- .../proxy/grpc/v2/adapter/RequestMapping.java | 16 ----- 2 files changed, 24 insertions(+), 51 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index cf16b347d5..da49e56106 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -16,16 +16,15 @@ */ package org.apache.rocketmq.acl.plain; -import apache.rocketmq.v1.AckMessageRequest; -import apache.rocketmq.v1.EndTransactionRequest; -import apache.rocketmq.v1.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v1.HeartbeatRequest; -import apache.rocketmq.v1.NackMessageRequest; -import apache.rocketmq.v1.PullMessageRequest; -import apache.rocketmq.v1.QueryOffsetRequest; -import apache.rocketmq.v1.ReceiveMessageRequest; -import apache.rocketmq.v1.Resource; -import apache.rocketmq.v1.SendMessageRequest; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.NackMessageRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; import com.google.protobuf.GeneratedMessageV3; import java.nio.charset.StandardCharsets; import java.util.List; @@ -47,6 +46,7 @@ import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.PlainAccessConfig; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; @@ -176,20 +176,22 @@ public class PlainAccessValidator implements AccessValidator { String rpcFullName = messageV3.getDescriptorForType().getFullName(); if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { HeartbeatRequest request = (HeartbeatRequest) messageV3; - if (request.hasProducerData()) { - Resource group = request.getProducerData() - .getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - } else if (request.hasConsumerData()) { - Resource group = request.getConsumerData() - .getGroup(); + if (request.hasGroup()) { + Resource group = request.getGroup(); String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); accessResource.addResourceAndPerm(groupName, Permission.SUB); } } else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { SendMessageRequest request = (SendMessageRequest) messageV3; - Resource topic = request.getMessage().getTopic(); + if (request.getMessagesCount() <= 0) { + throw new AclException("SendMessageRequest, messageCount is zero", ResponseCode.MESSAGE_ILLEGAL); + } + Resource topic = request.getMessages(0).getTopic(); + for (Message message : request.getMessagesList()) { + if (!message.getTopic().equals(topic)) { + throw new AclException("SendMessageRequest, messages' topic is not consistent", ResponseCode.MESSAGE_ILLEGAL); + } + } String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); accessResource.addResourceAndPerm(topicName, Permission.PUB); } else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { @@ -197,7 +199,7 @@ public class PlainAccessValidator implements AccessValidator { Resource group = request.getGroup(); String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getPartition().getTopic(); + Resource topic = request.getMessageQueue().getTopic(); String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); accessResource.addResourceAndPerm(topicName, Permission.SUB); } else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { @@ -226,22 +228,9 @@ public class PlainAccessValidator implements AccessValidator { accessResource.addResourceAndPerm(topicName, Permission.SUB); } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { EndTransactionRequest request = (EndTransactionRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.PUB); - } else if (QueryOffsetRequest.getDescriptor().getFullName().equals(rpcFullName)) { - QueryOffsetRequest request = (QueryOffsetRequest) messageV3; - Resource topic = request.getPartition().getTopic(); + Resource topic = request.getTopic(); String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); - } else if (PullMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - PullMessageRequest request = (PullMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getPartition().getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); + accessResource.addResourceAndPerm(topicName, Permission.PUB); } } catch (Throwable t) { throw new AclException(t.getMessage(), t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index d659c58598..eafca24f49 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -47,22 +47,6 @@ public class RequestMapping { put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - - // v1 - put(apache.rocketmq.v1.QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(apache.rocketmq.v1.HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(apache.rocketmq.v1.HealthCheckRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(apache.rocketmq.v1.SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); - put(apache.rocketmq.v1.QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(apache.rocketmq.v1.ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(apache.rocketmq.v1.AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); - put(apache.rocketmq.v1.NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(apache.rocketmq.v1.EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); - put(apache.rocketmq.v1.QueryOffsetRequest.getDescriptor().getFullName(), RequestCode.SEARCH_OFFSET_BY_TIMESTAMP); - put(apache.rocketmq.v1.PullMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(apache.rocketmq.v1.NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); - put(apache.rocketmq.v1.ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); } }; From 9b88806a837b48bd7bc7c185ad1f2d3f3d7e4849 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 28 Apr 2022 16:42:44 +0800 Subject: [PATCH 150/338] [ISSUE #3949] Remove unused finally --- .../proxy/grpc/v2/service/LocalGrpcService.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 5fa9cf55ad..6cb84a5c4b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -293,16 +293,11 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo channel.eraseInvocationContext(command.getOpaque()); future.completeExceptionally(e); } - future.thenAccept(r -> { - try { - writer.write(ctx, request, PopStatus.FOUND, r); - } finally { - responseObserver.onCompleted(); - } - }).exceptionally(e -> { - writer.write(ctx, request, e); - return null; - }); + future.thenAccept(r -> writer.write(ctx, request, PopStatus.FOUND, r)) + .exceptionally(e -> { + writer.write(ctx, request, e); + return null; + }); } @Override From 00216477041c7876b11aa7f34a735213c11ee35e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 28 Apr 2022 16:46:33 +0800 Subject: [PATCH 151/338] [ISSUE #3949] v2 support --- .../rocketmq/proxy/connector/ForwardProducer.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java index 10202aa5b9..12a7a8c1d2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java @@ -19,6 +19,8 @@ package org.apache.rocketmq.proxy.connector; import io.grpc.Context; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; @@ -114,16 +116,19 @@ public class ForwardProducer extends AbstractForwardClient { public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, AckMessageRequestHeader ackMessageRequestHeader) { - return sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader,DEFAULT_MQ_CLIENT_TIMEOUT); + return sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader, DEFAULT_MQ_CLIENT_TIMEOUT, + future -> { + }); } public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, - AckMessageRequestHeader ackMessageRequestHeader, long timeoutMillis) { + AckMessageRequestHeader ackMessageRequestHeader, long timeoutMillis, + Consumer> ackFutureSetter) { return this.sendMessageBack(ctx, brokerAddr, sendMsgBackRequestHeader, timeoutMillis).whenComplete((result, throwable) -> { if (throwable != null || ResponseCode.SUCCESS != result.getCode()) { return; } - this.getClient().ackMessageAsync(brokerAddr, ackMessageRequestHeader, timeoutMillis); + ackFutureSetter.accept(this.getClient().ackMessageAsync(brokerAddr, ackMessageRequestHeader, timeoutMillis)); }); } From 30aa97317b683954929e12b5e5ff8328d475eb5d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 28 Apr 2022 17:06:20 +0800 Subject: [PATCH 152/338] [ISSUE #3949] Pass checkstyle --- .../broker/client/ConsumerManagerTest.java | 16 ++++++++++++++++ pom.xml | 1 + .../connector/transaction/TransactionIdTest.java | 16 ++++++++++++++++ .../v2/service/cluster/ConsumerServiceTest.java | 16 ++++++++++++++++ .../cluster/DefaultReadQueueSelectorTest.java | 16 ++++++++++++++++ .../cluster/DefaultWriteQueueSelectorTest.java | 16 ++++++++++++++++ .../cluster/ForwardClientServiceTest.java | 16 ++++++++++++++++ .../service/cluster/TransactionServiceTest.java | 16 ++++++++++++++++ 8 files changed, 113 insertions(+) diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java index f6dbd3e973..8149cd624c 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java @@ -1,3 +1,19 @@ +/* + * 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.client; import io.netty.channel.Channel; diff --git a/pom.xml b/pom.xml index f32f831896..def3cb5cee 100644 --- a/pom.xml +++ b/pom.xml @@ -235,6 +235,7 @@ CONTRIBUTING.md bin/README.md .github/** + src/test/resources/** src/test/resources/certs/* src/test/**/*.log src/test/resources/META-INF/service/* diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java index ab4cfb0201..8636cf5954 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java @@ -1,3 +1,19 @@ +/* + * 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.connector.transaction; import java.net.UnknownHostException; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 0911a9956a..9f3dd94579 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -1,3 +1,19 @@ +/* + * 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.grpc.v2.service.cluster; import apache.rocketmq.v2.AckMessageEntry; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java index 823b7437fd..b7436d29bc 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java @@ -1,3 +1,19 @@ +/* + * 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.grpc.v2.service.cluster; import apache.rocketmq.v2.Broker; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java index a63561d7f3..013814cc45 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java @@ -1,3 +1,19 @@ +/* + * 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.grpc.v2.service.cluster; import apache.rocketmq.v2.Message; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java index ad1bb98c0e..2cb06da6ab 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -1,3 +1,19 @@ +/* + * 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.grpc.v2.service.cluster; import apache.rocketmq.v2.ClientType; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index cccfe03ee4..5c762e3f12 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -1,3 +1,19 @@ +/* + * 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.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; From afcade74cfaeb532c35c4fcf4e88fb07d3005d07 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 28 Apr 2022 17:39:30 +0800 Subject: [PATCH 153/338] [ISSUE #3949] v2 support --- .../header/AckMessageRequestHeader.java | 8 +++++++- .../ChangeInvisibleTimeRequestHeader.java | 4 ++-- .../CheckTransactionStateRequestHeader.java | 11 +++++++++++ .../header/CloneGroupOffsetRequestHeader.java | 10 ++++++++++ ...umeMessageDirectlyResultRequestHeader.java | 13 +++++++++++++ .../ConsumerSendMsgBackRequestHeader.java | 11 +++++++++-- .../CreateAccessConfigRequestHeader.java | 14 ++++++++++++++ .../header/CreateTopicRequestHeader.java | 16 ++++++++++++++++ .../header/GetConsumeStatsRequestHeader.java | 8 ++++++++ .../GetConsumerListByGroupRequestHeader.java | 7 +++++++ .../GetConsumerRunningInfoRequestHeader.java | 9 +++++++++ .../GetConsumerStatusRequestHeader.java | 9 +++++++++ .../header/GetMaxOffsetRequestHeader.java | 9 +++++++++ .../header/GetMinOffsetRequestHeader.java | 8 ++++++++ .../header/PopMessageRequestHeader.java | 17 +++++++++++++++++ .../header/PullMessageRequestHeader.java | 18 ++++++++++++++++++ .../header/SearchOffsetRequestHeader.java | 8 ++++++++ .../header/SendMessageRequestHeader.java | 19 +++++++++++++++++++ .../UpdateConsumerOffsetRequestHeader.java | 10 ++++++++++ .../connector/ForwardClientManagerTest.java | 2 ++ 20 files changed, 206 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java index 02e388ba4c..66721a4903 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java @@ -80,6 +80,12 @@ public class AckMessageRequestHeader implements CommandCustomHeader { @Override public String toString() { - return topic + "," + this.consumerGroup + "," + this.queueId + "," + this.offset + "," + this.extraInfo; + return "AckMessageRequestHeader{" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + ", queueId=" + queueId + + ", extraInfo='" + extraInfo + '\'' + + ", offset=" + offset + + '}'; } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java index f01e89c725..6c6f5bad9f 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java @@ -96,13 +96,13 @@ public class ChangeInvisibleTimeRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "ChangeInvisibleTimeRequestHeader [" + + return "ChangeInvisibleTimeRequestHeader{" + "consumerGroup='" + consumerGroup + '\'' + ", topic='" + topic + '\'' + ", queueId=" + queueId + ", extraInfo='" + extraInfo + '\'' + ", offset=" + offset + ", invisibleTime=" + invisibleTime + - ']'; + '}'; } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java index 6cba71c7e9..149de9b579 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java @@ -76,4 +76,15 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { public void setOffsetMsgId(String offsetMsgId) { this.offsetMsgId = offsetMsgId; } + + @Override + public String toString() { + return "CheckTransactionStateRequestHeader{" + + "tranStateTableOffset=" + tranStateTableOffset + + ", commitLogOffset=" + commitLogOffset + + ", msgId='" + msgId + '\'' + + ", transactionId='" + transactionId + '\'' + + ", offsetMsgId='" + offsetMsgId + '\'' + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java index afc017b2a6..e010649a4b 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java @@ -68,4 +68,14 @@ public class CloneGroupOffsetRequestHeader implements CommandCustomHeader { public void setOffline(boolean offline) { this.offline = offline; } + + @Override + public String toString() { + return "CloneGroupOffsetRequestHeader{" + + "srcGroup='" + srcGroup + '\'' + + ", destGroup='" + destGroup + '\'' + + ", topic='" + topic + '\'' + + ", offline=" + offline + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java index 7bad63985d..18298a6ea5 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java @@ -97,4 +97,17 @@ public class ConsumeMessageDirectlyResultRequestHeader implements CommandCustomH public void setGroupSysFlag(Integer groupSysFlag) { this.groupSysFlag = groupSysFlag; } + + @Override + public String toString() { + return "ConsumeMessageDirectlyResultRequestHeader{" + + "consumerGroup='" + consumerGroup + '\'' + + ", clientId='" + clientId + '\'' + + ", msgId='" + msgId + '\'' + + ", brokerName='" + brokerName + '\'' + + ", topic='" + topic + '\'' + + ", topicSysFlag=" + topicSysFlag + + ", groupSysFlag=" + groupSysFlag + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java index bd8fbb44ca..2e0a120a15 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java @@ -98,7 +98,14 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "ConsumerSendMsgBackRequestHeader [group=" + group + ", originTopic=" + originTopic + ", originMsgId=" + originMsgId - + ", delayLevel=" + delayLevel + ", unitMode=" + unitMode + ", maxReconsumeTimes=" + maxReconsumeTimes + "]"; + return "ConsumerSendMsgBackRequestHeader{" + + "offset=" + offset + + ", group='" + group + '\'' + + ", delayLevel=" + delayLevel + + ", originMsgId='" + originMsgId + '\'' + + ", originTopic='" + originTopic + '\'' + + ", unitMode=" + unitMode + + ", maxReconsumeTimes=" + maxReconsumeTimes + + '}'; } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java index 36990fcf64..c91ab11101 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java @@ -110,4 +110,18 @@ public class CreateAccessConfigRequestHeader implements CommandCustomHeader { public void setGroupPerms(String groupPerms) { this.groupPerms = groupPerms; } + + @Override + public String toString() { + return "CreateAccessConfigRequestHeader{" + + "accessKey='" + accessKey + '\'' + + ", secretKey='" + secretKey + '\'' + + ", whiteRemoteAddress='" + whiteRemoteAddress + '\'' + + ", admin=" + admin + + ", defaultTopicPerm='" + defaultTopicPerm + '\'' + + ", defaultGroupPerm='" + defaultGroupPerm + '\'' + + ", topicPerms='" + topicPerms + '\'' + + ", groupPerms='" + groupPerms + '\'' + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java index c3c59d4950..05c7195ac0 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java @@ -139,4 +139,20 @@ public class CreateTopicRequestHeader implements CommandCustomHeader { public void setAttributes(String attributes) { this.attributes = attributes; } + + @Override + public String toString() { + return "CreateTopicRequestHeader{" + + "topic='" + topic + '\'' + + ", defaultTopic='" + defaultTopic + '\'' + + ", readQueueNums=" + readQueueNums + + ", writeQueueNums=" + writeQueueNums + + ", perm=" + perm + + ", topicFilterType='" + topicFilterType + '\'' + + ", topicSysFlag=" + topicSysFlag + + ", order=" + order + + ", attributes='" + attributes + '\'' + + ", force=" + force + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java index 6ba069e1ff..7ce48bcee5 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java @@ -44,4 +44,12 @@ public class GetConsumeStatsRequestHeader implements CommandCustomHeader { public void setTopic(String topic) { this.topic = topic; } + + @Override + public String toString() { + return "GetConsumeStatsRequestHeader{" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java index 3523a52cae..3a8c482147 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java @@ -36,4 +36,11 @@ public class GetConsumerListByGroupRequestHeader implements CommandCustomHeader public void setConsumerGroup(String consumerGroup) { this.consumerGroup = consumerGroup; } + + @Override + public String toString() { + return "GetConsumerListByGroupRequestHeader [" + + "consumerGroup='" + consumerGroup + '\'' + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java index 1bbbd900c5..5f9bee4e93 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java @@ -57,4 +57,13 @@ public class GetConsumerRunningInfoRequestHeader implements CommandCustomHeader public void setJstackEnable(boolean jstackEnable) { this.jstackEnable = jstackEnable; } + + @Override + public String toString() { + return "GetConsumerRunningInfoRequestHeader{" + + "consumerGroup='" + consumerGroup + '\'' + + ", clientId='" + clientId + '\'' + + ", jstackEnable=" + jstackEnable + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java index ca26a869c6..d77acda8cd 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java @@ -57,4 +57,13 @@ public class GetConsumerStatusRequestHeader implements CommandCustomHeader { public void setClientAddr(String clientAddr) { this.clientAddr = clientAddr; } + + @Override + public String toString() { + return "GetConsumerStatusRequestHeader{" + + "topic='" + topic + '\'' + + ", group='" + group + '\'' + + ", clientAddr='" + clientAddr + '\'' + + '}'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java index f58e050da7..1883eecc12 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java @@ -71,4 +71,13 @@ public class GetMaxOffsetRequestHeader extends TopicQueueRequestHeader { public void setCommitted(final boolean committed) { this.committed = committed; } + + @Override + public String toString() { + return "GetMaxOffsetRequestHeader [" + + "topic='" + topic + '\'' + + ", queueId=" + queueId + + ", committed=" + committed + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java index 70189b74b5..b205326f67 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java @@ -53,4 +53,12 @@ public class GetMinOffsetRequestHeader extends TopicQueueRequestHeader { public void setQueueId(Integer queueId) { this.queueId = queueId; } + + @Override + public String toString() { + return "GetMinOffsetRequestHeader [" + + "topic='" + topic + '\'' + + ", queueId=" + queueId + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java index 4d151a23e0..c90a26a334 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java @@ -152,4 +152,21 @@ public class PopMessageRequestHeader implements CommandCustomHeader { public boolean isOrder() { return this.order != null && this.order.booleanValue(); } + + @Override + public String toString() { + return "PopMessageRequestHeader [" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + ", queueId=" + queueId + + ", maxMsgNums=" + maxMsgNums + + ", invisibleTime=" + invisibleTime + + ", pollTime=" + pollTime + + ", bornTime=" + bornTime + + ", initMode=" + initMode + + ", expType='" + expType + '\'' + + ", exp='" + exp + '\'' + + ", order=" + order + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java index 08790fc294..bbcd813973 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java @@ -154,4 +154,22 @@ public class PullMessageRequestHeader extends TopicQueueRequestHeader { public void setMaxMsgBytes(Integer maxMsgBytes) { this.maxMsgBytes = maxMsgBytes; } + + @Override + public String toString() { + return "PullMessageRequestHeader [" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + ", queueId=" + queueId + + ", queueOffset=" + queueOffset + + ", maxMsgBytes=" + maxMsgBytes + + ", maxMsgNums=" + maxMsgNums + + ", sysFlag=" + sysFlag + + ", commitOffset=" + commitOffset + + ", suspendTimeoutMillis=" + suspendTimeoutMillis + + ", subscription='" + subscription + '\'' + + ", subVersion=" + subVersion + + ", expressionType='" + expressionType + '\'' + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java index c8291d2665..1fcab60db5 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java @@ -65,4 +65,12 @@ public class SearchOffsetRequestHeader extends TopicQueueRequestHeader { this.timestamp = timestamp; } + @Override + public String toString() { + return "SearchOffsetRequestHeader [" + + "topic='" + topic + '\'' + + ", queueId=" + queueId + + ", timestamp=" + timestamp + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java index 808bc2d3d5..cc4db84032 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java @@ -163,4 +163,23 @@ public class SendMessageRequestHeader extends TopicQueueRequestHeader { public void setBatch(boolean batch) { this.batch = batch; } + + @Override + public String toString() { + return "SendMessageRequestHeader [" + + "producerGroup='" + producerGroup + '\'' + + ", topic='" + topic + '\'' + + ", defaultTopic='" + defaultTopic + '\'' + + ", defaultTopicQueueNums=" + defaultTopicQueueNums + + ", queueId=" + queueId + + ", sysFlag=" + sysFlag + + ", bornTimestamp=" + bornTimestamp + + ", flag=" + flag + + ", properties='" + properties + '\'' + + ", reconsumeTimes=" + reconsumeTimes + + ", unitMode=" + unitMode + + ", batch=" + batch + + ", maxReconsumeTimes=" + maxReconsumeTimes + + ']'; + } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java index 11eccd5c1e..5b47211e67 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java @@ -73,4 +73,14 @@ public class UpdateConsumerOffsetRequestHeader extends TopicQueueRequestHeader { public void setCommitOffset(Long commitOffset) { this.commitOffset = commitOffset; } + + @Override + public String toString() { + return "UpdateConsumerOffsetRequestHeader [" + + "consumerGroup='" + consumerGroup + '\'' + + ", topic='" + topic + '\'' + + ", queueId=" + queueId + + ", commitOffset=" + commitOffset + + ']'; + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java index 01d89f4472..0cd627411a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java @@ -29,6 +29,8 @@ public class ForwardClientManagerTest extends InitConfigAndLoggerTest { @Test public void testConnectorManager() throws Exception { + ConfigurationManager.getProxyConfig().setNameSrvAddr("127.0.0.1:9876"); + TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); ConnectorManager connectorManager = new ConnectorManager(mockedTransactionStateChecker); connectorManager.start(); From b7fa178d83a9219360b8b7b36c18707964df021a Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 28 Apr 2022 19:39:10 +0800 Subject: [PATCH 154/338] [ISSUE #3949] Fix unit test --- .../rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index a290c62439..78d7935293 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -140,7 +140,6 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); - Mockito.when(brokerControllerMock.getMessageStoreConfig()).thenReturn(new MessageStoreConfig()); Mockito.when(brokerControllerMock.getTopicConfigManager()).thenReturn(topicConfigManagerMock); Mockito.when(topicConfigManagerMock.selectTopicConfig(Mockito.anyString())).thenReturn(new TopicConfig("topic", 8, 8)); Mockito.doNothing().when(consumerManagerMock).appendConsumerIdsChangeListener(Mockito.any(ConsumerIdsChangeListener.class)); From caeb5c175f7733f4142c6947bfa3a597d7b5f72b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 29 Apr 2022 14:28:14 +0800 Subject: [PATCH 155/338] [ISSUE #3949] Add integration testing --- .../rocketmq/test/grpc/v2/ClusterGrpcTest.java | 2 -- .../apache/rocketmq/test/grpc/v2/LocalGrpcTest.java | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 84fa336a3e..431b236f83 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -61,7 +61,6 @@ public class ClusterGrpcTest extends GrpcBaseTest { @Test public void testQueryRoute() throws Exception { String topic = initTopic(); - this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); assertQueryRoute(response, brokerNum * defaultQueueNums); @@ -71,7 +70,6 @@ public class ClusterGrpcTest extends GrpcBaseTest { public void testQueryAssignment() throws Exception { String topic = initTopic(); String group = "group"; - this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); QueryAssignmentResponse response = blockingStub.queryAssignment(buildQueryAssignmentRequest(topic, group)); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index 6ddefba797..d28f4311fd 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.test.grpc.v2; +import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteResponse; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; @@ -46,12 +47,21 @@ public class LocalGrpcTest extends GrpcBaseTest { @Test public void testQueryRoute() throws Exception { String topic = initTopic(); - this.sendClientSettings(stub, buildAccessPointClientSettings(PORT)).get(); QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); assertQueryRoute(response, brokerControllerList.size() * defaultQueueNums); } + @Test + public void testQueryAssignment() throws Exception { + String topic = initTopic(); + String group = "group"; + + QueryAssignmentResponse response = blockingStub.queryAssignment(buildQueryAssignmentRequest(topic, group)); + + assertQueryAssignment(response, brokerNum); + } + @Test public void testSendReceiveMessage() throws Exception { super.testSendReceiveMessage(); From 86284b4e1e40190d1345775d73ab56c836d10cbc Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 29 Apr 2022 15:36:41 +0800 Subject: [PATCH 156/338] [ISSUE #3949] Modify default configuration location --- distribution/conf/rmq-proxy.json | 3 +++ .../apache/rocketmq/proxy/config/ConfigurationManager.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 distribution/conf/rmq-proxy.json diff --git a/distribution/conf/rmq-proxy.json b/distribution/conf/rmq-proxy.json new file mode 100644 index 0000000000..077404aaa4 --- /dev/null +++ b/distribution/conf/rmq-proxy.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java index 6efecf5e73..61e4498962 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java @@ -17,12 +17,12 @@ package org.apache.rocketmq.proxy.config; -import java.io.File; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.MixAll; public class ConfigurationManager { public static final String RMQ_PROXY_HOME = "RMQ_PROXY_HOME"; - protected static final String DEFAULT_RMQ_PROXY_HOME = System.getProperty("user.home") + File.separator + "rmq-proxy"; + protected static final String DEFAULT_RMQ_PROXY_HOME = System.getenv(MixAll.ROCKETMQ_HOME_ENV); protected static String proxyHome; protected static Configuration configuration; From 2a53918817720dd08cb5a76e010d763cbfc3f1f1 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 29 Apr 2022 15:36:54 +0800 Subject: [PATCH 157/338] [ISSUE #3949] Add deploy guide --- docs/en/README.md | 3 +++ docs/en/proxy/deploy_guide.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 docs/en/proxy/deploy_guide.md diff --git a/docs/en/README.md b/docs/en/README.md index b24d2403fd..79703efbe1 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -33,6 +33,9 @@ - [Cluster Deployment](dledger/deploy_guide.md):introduce how to deploy Dledger in cluster. +- [GRPC Proxy Deployment](proxy/deploy_guide.md) +Introduce how to deploy gRPC proxy (both `Local` mode and `Cluster` mode). + ### 5. Operation and maintenance management - [Operation](operation.md):introduce RocketMQ's deployment modes that including single-master mode, multi-master mode, multi-master multi-slave mode and so on, as well as the usage of operation tool mqadmin. diff --git a/docs/en/proxy/deploy_guide.md b/docs/en/proxy/deploy_guide.md new file mode 100644 index 0000000000..6447d5b6b0 --- /dev/null +++ b/docs/en/proxy/deploy_guide.md @@ -0,0 +1,32 @@ +# RocketMQ Proxy Deployment Guide + +## Overview +RocketMQ Proxy supports two deployment modes, `Local` mode and `Cluster` mode. + +With `Local` mode, `Proxy` deployed with `Broker` in the same process with inter-process communication. + +While `Cluster` mode, `Proxy` is a single cluster who communicate `Broker` with remote procedure call. In this way, `Proxy` acts as a stateless computing components while `Broker` is a stateful components with local storage. This form of deployment makes RocketMQ an architecture of separation of computing and storage. + +## Configuration +The configuration applies to both the `Cluster` mode and `Local` mode, whose default path is distribution/conf/rmq-proxy.json directory. + +## `Cluster` mode +* Set configuration field `nameSrvAddr`. +* Set configuration field `proxyMode` to `cluster` (case insensitive). + + +Run the command below. +```shell +nohup sh mqproxy & +``` +The command will only run `Proxy` itself. It requires `Namesrv` and `Broker` components running. + +## `Local` mode +* Set configuration field `nameSrvAddr`. +* Set configuration field `proxyMode` to `local` (case insensitive). + +Run the command below. +```shell +nohup sh mqproxy & +``` +The command will not only run `Proxy`, but also run `Broker`. It requires `Namesrv` only and there's no need for extra `Broker`. \ No newline at end of file From 78aaf3b19c386802486f7f18017be76856872927 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 29 Apr 2022 15:59:59 +0800 Subject: [PATCH 158/338] [ISSUE #3949] Format and clean code --- .../rocketmq/proxy/channel/SimpleChannel.java | 5 -- .../rocketmq/proxy/common/DelayPolicy.java | 83 ------------------- .../connector/client/MQClientAPIExt.java | 4 +- .../factory/AbstractClientManager.java | 2 +- .../v2/adapter/channel/GrpcClientChannel.java | 5 +- .../grpc/v2/service/LocalGrpcServiceTest.java | 1 - .../v2/service/cluster/BaseServiceTest.java | 3 +- .../service/cluster/ProducerServiceTest.java | 5 +- 8 files changed, 6 insertions(+), 102 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java index a9869ec1e6..cd3a5a9bed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java @@ -166,11 +166,6 @@ public class SimpleChannel extends AbstractChannel { return null; } - @Override - public EventLoop eventLoop() { - return super.eventLoop(); - } - @Override public ChannelFuture writeAndFlush(Object msg) { DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java deleted file mode 100644 index b0220e14e1..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/DelayPolicy.java +++ /dev/null @@ -1,83 +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.proxy.common; - -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class DelayPolicy { - private List delayIntervalList; - - private DelayPolicy(List delayIntervalList) { - this.delayIntervalList = delayIntervalList; - } - - public long getDelayInterval(int index) { - int size = delayIntervalList.size(); - if (index >= size) { - throw new IllegalArgumentException("Out of index, size: " + size); - } - return delayIntervalList.get(index); - } - - public void refresh(String messageDelayLevel) { - delayIntervalList = buildList(messageDelayLevel); - } - - public static DelayPolicy build(String messageDelayLevel) { - return new DelayPolicy(buildList(messageDelayLevel)); - } - - private static List buildList(String messageDelayLevel) { - List delayLevelList = Lists.newArrayList(Splitter.on(" ").split(messageDelayLevel)); - List delayIntervalList = new ArrayList<>(); - // the index of messageDelayLevel start from 1, so add a default value - delayIntervalList.add(0L); - for (String delayLevel : delayLevelList) { - final Pattern p = Pattern.compile("(\\d+)([smhd])"); - final Matcher m = p.matcher(delayLevel); - while (m.find()) { - final int duration = Integer.parseInt(m.group(1)); - final String timeUnitString = m.group(2); - final long interval = toInterval(duration, timeUnitString); - delayIntervalList.add(interval); - } - } - return delayIntervalList; - } - - private static long toInterval(int duration, final String timeUnitString) { - switch (timeUnitString) { - case "s": - return TimeUnit.SECONDS.toMillis(duration); - case "m": - return TimeUnit.MINUTES.toMillis(duration); - case "h": - return TimeUnit.HOURS.toMillis(duration); - case "d": - return TimeUnit.DAYS.toMillis(duration); - default: - throw new IllegalArgumentException(String.format("%s is not a valid code [smhd]", timeUnitString)); - } - } -} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java index f84fc38973..47e204e579 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java @@ -360,8 +360,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { return; } } - /** - * @see org.apache.rocketmq.broker.processor.ConsumerManageProcessor#getConsumerListByGroup, + /* + @see org.apache.rocketmq.broker.processor.ConsumerManageProcessor#getConsumerListByGroup, * broker will return {@link ResponseCode.SYSTEM_ERROR} if there is no consumer. */ case ResponseCode.SYSTEM_ERROR: { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java index 4a6f0591ca..35e4f696bf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java @@ -37,7 +37,7 @@ public abstract class AbstractClientManager { this.rpcHook = rpcHook; } - protected abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) throws Throwable; + protected abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads); protected abstract boolean tryStart(T t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index 7966ab7410..cd82c34d1b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -96,10 +96,7 @@ public class GrpcClientChannel extends SimpleChannel { @Override public boolean isWritable() { - if (this.telemetryCommandRef.get() == null) { - return false; - } - return true; + return this.telemetryCommandRef.get() != null; } /** diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 78d7935293..17a1451fd9 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -94,7 +94,6 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.apache.rocketmq.store.config.MessageStoreConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java index 1a05c8675e..0d35cfbe5f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java @@ -31,11 +31,10 @@ import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.DefaultForwardClient; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.junit.Before; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index fee74d2176..2b205e2298 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; @@ -148,9 +147,7 @@ public class ProducerServiceTest extends BaseServiceTest { producerService.setWriteQueueSelector((ctx, request) -> { throw ex; }); - producerService.setSendMessageHook((ctx, request, response, t) -> { - assertSame(ex, t); - }); + producerService.setSendMessageHook((ctx, request, response, t) -> assertSame(ex, t)); CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); From 6d57eef4c928703e0a3b4f7dfc9f0f8548b0b301 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 29 Apr 2022 17:53:08 +0800 Subject: [PATCH 159/338] [ISSUE #3949] Add unit test --- .../service/cluster/ConsumerServiceTest.java | 38 +++++ ...eceiveMessageResponseStreamWriterTest.java | 159 ++++++++++++++++++ .../LocalReceiveMessageResultFilterTest.java | 135 +++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 9f3dd94579..7857f207d2 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -19,6 +19,8 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; @@ -31,6 +33,8 @@ import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; +import com.google.protobuf.Duration; +import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.List; @@ -281,6 +285,40 @@ public class ConsumerServiceTest extends BaseServiceTest { assertEquals(receiptHandle.encode(), headerArgumentCaptor.getValue().getExtraInfo()); } + @Test + public void testChangeInvisibleDuration() throws Exception { + Duration newDuration = Duration.newBuilder() + .setSeconds(3).build(); + ReceiptHandle receiptHandle = createReceiptHandle(); + ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.OK); + ackResult.setExtraInfo(receiptHandle.encode()); + when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), anyString(), headerArgumentCaptor.capture())) + .thenReturn(CompletableFuture.completedFuture(ackResult)); + when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + + Settings clientSettings = createClientSettings(3); + when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); + + ChangeInvisibleDurationResponse response = consumerService.changeInvisibleDuration(Context.current(), ChangeInvisibleDurationRequest.newBuilder() + .setTopic(Resource.newBuilder() + .setName("topic") + .build()) + .setGroup(Resource.newBuilder() + .setName("group") + .build()) + .setReceiptHandle(receiptHandle.encode()) + .setInvisibleDuration(newDuration) + .build()) + .get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(receiptHandle.getOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); + assertEquals(receiptHandle.encode(), headerArgumentCaptor.getValue().getExtraInfo()); + assertEquals(Durations.toMillis(newDuration), headerArgumentCaptor.getValue().getInvisibleTime().longValue()); + } + private Settings createClientSettings(int maxDeliveryAttempts) { return Settings.newBuilder() .setBackoffPolicy(RetryPolicy.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java new file mode 100644 index 0000000000..5a53f5861a --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java @@ -0,0 +1,159 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.Context; +import io.grpc.stub.ServerCallStreamObserver; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(MockitoJUnitRunner.class) +public class LocalReceiveMessageResponseStreamWriterTest { + @Mock + private ServerCallStreamObserver streamObserverMock; + @Mock + private ChannelManager channelManagerMock; + @Mock + private BrokerController brokerControllerMock; + @Mock + private ReceiveMessageResultFilter receiveMessageResultFilterMock; + @Mock + private ChangeInvisibleTimeProcessor changeInvisibleTimeProcessorMock; + + private LocalReceiveMessageResponseStreamWriter localReceiveMessageResponseStreamWriter; + + @Before + public void setup() { + Mockito.when(receiveMessageResultFilterMock.filterMessage(Mockito.any(), Mockito.any(), Mockito.anyList())).thenAnswer((Answer>) invocation -> { + List messageList = new ArrayList<>(); + List messageExtList = invocation.getArgument(2); + for (MessageExt messageExt : messageExtList) { + messageList.add(GrpcConverter.buildMessage(messageExt)); + } + return messageList; + }); + localReceiveMessageResponseStreamWriter + = new LocalReceiveMessageResponseStreamWriter(streamObserverMock, null, channelManagerMock, brokerControllerMock, receiveMessageResultFilterMock); + } + + @Test + public void testWrite() { + MessageExt messageExt = new MessageExt(); + messageExt.setTopic("topic"); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); + messageExt.putUserProperty("key", "value"); + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topicType("0") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()); + messageExt.putUserProperty("key", "value"); + List messageExtList = new ArrayList<>(); + messageExtList.add(messageExt); + localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); + ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + Mockito.verify(streamObserverMock, Mockito.times(2)).onNext(argument.capture()); + assertThat(argument.getAllValues().get(0)).isEqualTo(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build()); + assertThat(argument.getAllValues().get(1)).isEqualTo(ReceiveMessageResponse.newBuilder() + .setMessage(GrpcConverter.buildMessage(messageExt)).build()); + } + + @Test + public void testWriteWhenNoMessage() { + localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, new ArrayList<>()); + Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")).build())); + } + + @Test + public void testWriteWhenCancel() throws RemotingCommandException { + Mockito.when(streamObserverMock.isCancelled()).thenReturn(true); + Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); + MessageExt messageExt = new MessageExt(); + messageExt.setTopic("topic"); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); + messageExt.putUserProperty("key", "value"); + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topicType("0") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()); + messageExt.putUserProperty("key", "value"); + List messageExtList = new ArrayList<>(); + messageExtList.add(messageExt); + localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); + Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build())); + Mockito.verify(changeInvisibleTimeProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.any()); + } + + @Test + public void testWriteError() { + String info = "error"; + localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), new ProxyException(Code.ILLEGAL_MESSAGE, info)); + Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_MESSAGE, info)).build())); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java new file mode 100644 index 0000000000..20dbce41a7 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java @@ -0,0 +1,135 @@ +/* + * 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.grpc.v2.service.local; + +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Settings; +import io.grpc.Context; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.AckMessageProcessor; +import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.channel.ChannelManager; +import org.apache.rocketmq.proxy.channel.SimpleChannel; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class LocalReceiveMessageResultFilterTest extends InitConfigAndLoggerTest { + @Mock + private ChannelManager channelManagerMock; + @Mock + private BrokerController brokerControllerMock; + @Mock + private GrpcClientManager grpcClientManagerMock; + @Mock + private AckMessageProcessor ackMessageProcessorMock; + @Mock + private SendMessageProcessor sendMessageProcessorMock; + + private String topic = "topic"; + + @Test + public void testFilterMessageWhenNotMatch() throws RemotingCommandException { + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); + Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); + Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); + Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); + Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); + List messageExtList = new ArrayList<>(); + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); + messageExt.putUserProperty("key", "value"); + messageExt.setTags("b"); + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topicType("0") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()); + messageExtList.add(messageExt); + LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); + localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() + .setFilterExpression(FilterExpression.newBuilder() + .setExpression("a").build()).build(), messageExtList); + Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); + } + + @Test + public void testFilterMessageWhenDLQ() throws RemotingCommandException { + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); + Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); + Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); + Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); + Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); + Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); + List messageExtList = new ArrayList<>(); + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setQueueOffset(0L); + messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); + messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); + messageExt.putUserProperty("key", "value"); + messageExt.setTags("a"); + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0L) + .invisibleTime(1000L) + .nextVisibleTime(1000L) + .reviveQueueId(0) + .topicType("0") + .brokerName("brokerName") + .queueId(0) + .offset(0L) + .build().encode()); + messageExtList.add(messageExt); + LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); + localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() + .setFilterExpression(FilterExpression.newBuilder() + .setExpression("a").build()).build(), messageExtList); + Mockito.verify(sendMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK)); + Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); + } +} \ No newline at end of file From 3ede21afbbb4ab9f916dd1e52e0937ccaf8379d1 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 5 May 2022 15:16:37 +0800 Subject: [PATCH 160/338] [ISSUE #3949] v2 support --- .../ReceiveMessageResponseStreamWriter.java | 79 ++++++++++++++++- ...ultReceiveMessageResponseStreamWriter.java | 85 +------------------ ...calReceiveMessageResponseStreamWriter.java | 75 +--------------- .../grpc/v2/service/LocalGrpcServiceTest.java | 3 +- ...eceiveMessageResponseStreamWriterTest.java | 13 ++- 5 files changed, 98 insertions(+), 157 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java index 8723558b71..32998280f2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java @@ -16,19 +16,25 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.util.Iterator; import java.util.List; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; public abstract class ReceiveMessageResponseStreamWriter { protected final StreamObserver streamObserver; protected final ResponseHook receiveMessageHook; + protected final ReceiveMessageResultFilter receiveMessageResultFilter; public interface Builder { ReceiveMessageResponseStreamWriter build( @@ -38,12 +44,79 @@ public abstract class ReceiveMessageResponseStreamWriter { public ReceiveMessageResponseStreamWriter( StreamObserver observer, - ResponseHook hook) { + ResponseHook hook, + ReceiveMessageResultFilter messageResultFilter) { streamObserver = observer; receiveMessageHook = hook; + receiveMessageResultFilter = messageResultFilter; } - public abstract void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList); + public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + try { + switch (status) { + case FOUND: + List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); + if (messageList.isEmpty()) { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + } else { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + Iterator messageIterator = messageList.iterator(); + while (messageIterator.hasNext()) { + Message curMessage = messageIterator.next(); + try { + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setMessage(curMessage) + .build()); + } catch (Throwable t) { + this.processThrowableWhenWriteMessage(t, ctx, request, curMessage); + messageIterator.forEachRemaining(message -> + this.processThrowableWhenWriteMessage(t, ctx, request, message)); + return; + } + } + } + break; + case POLLING_FULL: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .build()); + break; + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) + .build()); + break; + } + } catch (Throwable t) { + write(ctx, request, t); + } finally { + responseStreamObserver.onCompleted(); + } + } - public abstract void write(Context ctx, ReceiveMessageRequest request, Throwable throwable); + protected abstract void processThrowableWhenWriteMessage(Throwable throwable, + Context context, ReceiveMessageRequest request, Message message); + + public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { + ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( + ctx, + request, + receiveMessageHook, + streamObserver); + ResponseWriter.write( + responseStreamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() + ); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index 0c8f50547a..bf071719f3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -16,31 +16,23 @@ */ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.time.Duration; -import java.util.Iterator; -import java.util.List; import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamObserver; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; @@ -50,7 +42,6 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); protected final ForwardWriteConsumer writeConsumer; protected final TopicRouteCache topicRouteCache; - protected volatile ReceiveMessageResultFilter receiveMessageResultFilter; public DefaultReceiveMessageResponseStreamWriter( StreamObserver observer, @@ -58,74 +49,15 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes ForwardWriteConsumer writeConsumer, TopicRouteCache topicRouteCache, ReceiveMessageResultFilter receiveMessageResultFilter) { - super(observer, hook); + super(observer, hook, receiveMessageResultFilter); this.writeConsumer = writeConsumer; this.topicRouteCache = topicRouteCache; - this.receiveMessageResultFilter = receiveMessageResultFilter; } @Override - public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - try { - switch (status) { - case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); - if (messageList.isEmpty()) { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - } else { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - Iterator messageIterator = messageList.iterator(); - while (messageIterator.hasNext()) { - if (responseStreamObserver.isCancelled()) { - break; - } - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setMessage(messageIterator.next()) - .build()); - } - messageIterator.forEachRemaining(message -> this.nackFailToWriteMessage(ctx, request, message)); - } - break; - case POLLING_FULL: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build()); - break; - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - break; - } - } catch (Throwable t) { - write(ctx, request, t); - } finally { - responseStreamObserver.onCompleted(); - } - } - - @Override - public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - ResponseWriter.write( - responseStreamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() - ); + protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, + Message message) { + this.nackFailToWriteMessage(context, request, message); } protected void nackFailToWriteMessage(Context ctx, ReceiveMessageRequest request, Message message) { @@ -161,13 +93,4 @@ public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageRes log.warn("err when nack message. request:{}, message:{}", request, message, t); } } - - public ReceiveMessageResultFilter getReceiveMessageResultFilter() { - return receiveMessageResultFilter; - } - - public void setReceiveMessageResultFilter( - ReceiveMessageResultFilter receiveMessageResultFilter) { - this.receiveMessageResultFilter = receiveMessageResultFilter; - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java index 258afd1058..50fe0e1a59 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java @@ -17,29 +17,21 @@ package org.apache.rocketmq.proxy.grpc.v2.service.local; -import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.Channel; -import java.util.Iterator; -import java.util.List; import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamObserver; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -51,7 +43,6 @@ public class LocalReceiveMessageResponseStreamWriter extends ReceiveMessageRespo private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ChannelManager channelManager; private final BrokerController brokerController; - private final ReceiveMessageResultFilter receiveMessageResultFilter; public LocalReceiveMessageResponseStreamWriter( StreamObserver observer, @@ -59,73 +50,15 @@ public class LocalReceiveMessageResponseStreamWriter extends ReceiveMessageRespo ChannelManager channelManager, BrokerController brokerController, ReceiveMessageResultFilter receiveMessageResultFilter) { - super(observer, hook); + super(observer, hook, receiveMessageResultFilter); this.channelManager = channelManager; this.brokerController = brokerController; - this.receiveMessageResultFilter = receiveMessageResultFilter; } @Override - public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - try { - switch (status) { - case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); - if (messageList.isEmpty()) { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - } else { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - Iterator messageIterator = messageList.iterator(); - while (messageIterator.hasNext()) { - if (responseStreamObserver.isCancelled()) { - break; - } - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setMessage(messageIterator.next()) - .build()); - } - messageIterator.forEachRemaining(message -> this.changeInvisibleTime(ctx, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle()))); - } - break; - case POLLING_FULL: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build()); - break; - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - break; - } - } catch (Throwable t) { - write(ctx, request, t); - } finally { - responseStreamObserver.onCompleted(); - } - } - - @Override public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - ResponseWriter.write( - responseStreamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() - ); + protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, + Message message) { + this.changeInvisibleTime(context, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle())); } private void changeInvisibleTime(Context ctx, ReceiveMessageRequest request, ReceiptHandle handle) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 17a1451fd9..dc07124b75 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -91,6 +91,7 @@ import org.apache.rocketmq.proxy.connector.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -338,7 +339,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { .setSystemProperties( message.getSystemProperties() .toBuilder() - .setReceiptHandle("0 0 1000 0 0 zhouxiang_MBP16 0 0 0") + .setReceiptHandle("0 0 1000 0 0 "+ brokerControllerMock.getBrokerConfig().getBrokerName() +" 0 0 0") .build()) .build()) .build(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java index 5a53f5861a..a560673503 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java @@ -22,11 +22,14 @@ import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import io.grpc.Context; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import io.grpc.stub.ServerCallStreamObserver; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; import org.apache.rocketmq.client.consumer.PopStatus; @@ -45,6 +48,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; @@ -120,7 +124,14 @@ public class LocalReceiveMessageResponseStreamWriterTest { @Test public void testWriteWhenCancel() throws RemotingCommandException { - Mockito.when(streamObserverMock.isCancelled()).thenReturn(true); + AtomicInteger onNextCallTimes = new AtomicInteger(0); + Mockito.doAnswer(mock -> { + if (onNextCallTimes.get() <=0) { + onNextCallTimes.incrementAndGet(); + return null; + } + throw new StatusRuntimeException(Status.CANCELLED); + }).when(streamObserverMock).onNext(Mockito.any()); Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); MessageExt messageExt = new MessageExt(); messageExt.setTopic("topic"); From 2d594814b89c28277fabd95fc2c94d6264c10b14 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 29 Apr 2022 11:35:30 +0800 Subject: [PATCH 161/338] [ISSUE #3949] allow to config interceptor during building steps. --- .../apache/rocketmq/proxy/ProxyStartup.java | 1 + .../proxy/grpc/GrpcServerBuilder.java | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) 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 9d5a8766f1..1ba8feb444 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -68,6 +68,7 @@ public class ProxyStartup { // create grpcServer GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor) .addService(createServiceProcessor()) + .configInterceptor() .build(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); 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 04cac43db3..0c4be76384 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 @@ -27,9 +27,10 @@ import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel; import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.grpc.netty.shaded.io.netty.handler.ssl.util.SelfSignedCertificate; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import java.security.cert.CertificateException; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; @@ -83,8 +84,6 @@ public class GrpcServerBuilder { .executor(executor); } - configInterceptor(serverBuilder); - log.info( "grpc server has built. port: {}, tlsKeyPath: {}, tlsCertPath: {}, threadPool: {}, queueCapacity: {}, " + "boosLoop: {}, workerLoop: {}, maxInboundMessageSize: {}", @@ -122,8 +121,8 @@ public class GrpcServerBuilder { String tlsKeyPath = ConfigurationManager.getProxyConfig().getGrpcTlsKeyPath(); String tlsCertPath = ConfigurationManager.getProxyConfig().getGrpcTlsCertPath(); - try (InputStream serverKeyInputStream = new FileInputStream(tlsKeyPath); - InputStream serverCertificateStream = new FileInputStream(tlsCertPath)) { + try (InputStream serverKeyInputStream = Files.newInputStream(Paths.get(tlsKeyPath)); + InputStream serverCertificateStream = Files.newInputStream(Paths.get(tlsCertPath))) { serverBuilder.sslContext(GrpcSslContexts.forServer(serverCertificateStream, serverKeyInputStream) .trustManager(InsecureTrustManagerFactory.INSTANCE) .clientAuth(ClientAuth.NONE) @@ -134,17 +133,21 @@ public class GrpcServerBuilder { } } - protected void configInterceptor(NettyServerBuilder serverBuilder) { + public GrpcServerBuilder configInterceptor() { // grpc interceptors, including acl, logging etc. if (ConfigurationManager.getProxyConfig().isEnableACL()) { List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); if (accessValidators.isEmpty()) { throw new IllegalArgumentException("Load AccessValidator failed"); } - serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); + this.serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); } - serverBuilder.intercept(new ContextInterceptor()) + this.serverBuilder + .intercept(new ContextInterceptor()) .intercept(new HeaderInterceptor()); + + return this; } + } From d08dfce4fc4f344fc4331f859097f180abe1417b Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 29 Apr 2022 15:11:35 +0800 Subject: [PATCH 162/338] [ISSUE #3949] allow to add user-defined gRPC Server interceptors. --- .../org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java | 6 ++++++ .../proxy/grpc/interceptor/InterceptorConstants.java | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) 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 0c4be76384..02e6d3a9df 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 @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc; import io.grpc.BindableService; +import io.grpc.ServerInterceptor; import io.grpc.ServerServiceDefinition; import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; @@ -100,6 +101,11 @@ public class GrpcServerBuilder { return this; } + public GrpcServerBuilder appendInterceptor(ServerInterceptor interceptor) { + this.serverBuilder.intercept(interceptor); + return this; + } + public GrpcServer build() { return new GrpcServer(this.serverBuilder.build()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index 04d5137e14..0fe16789dd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -21,9 +21,6 @@ import io.grpc.Context; import io.grpc.Metadata; public class InterceptorConstants { - private InterceptorConstants() { - } - public static final Context.Key METADATA = Context.key("rpc-metadata"); /** From 67d749b569d054e7aabb952ca015e00c5f82c662 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 5 May 2022 17:44:04 +0800 Subject: [PATCH 163/338] [ISSUE #3949] v2 support --- .../acl/plain/PlainAccessValidator.java | 9 -- ...ractTransactionalMessageCheckListener.java | 1 + .../CheckTransactionStateRequestHeader.java | 12 +- .../ProxyClientRemotingProcessor.java | 1 + .../TransactionStateCheckRequest.java | 11 ++ .../proxy/grpc/v2/GrpcMessagingProcessor.java | 15 --- .../proxy/grpc/v2/adapter/GrpcConverter.java | 65 ++++------- .../proxy/grpc/v2/adapter/RequestMapping.java | 2 - .../v2/adapter/channel/GrpcClientChannel.java | 1 + ...seReceiveMessageResponseStreamWriter.java} | 6 +- .../BaseReceiveMessageResultFilter.java | 67 ++++++++++++ .../grpc/v2/service/ClusterGrpcService.java | 7 -- .../grpc/v2/service/GrpcForwardService.java | 4 - .../grpc/v2/service/LocalGrpcService.java | 51 +-------- .../v2/service/cluster/ConsumerService.java | 92 +--------------- ...ultReceiveMessageResponseStreamWriter.java | 4 +- .../DefaultReceiveMessageResultFilter.java | 103 ++++++------------ .../service/cluster/TransactionService.java | 5 +- ...calReceiveMessageResponseStreamWriter.java | 4 +- .../LocalReceiveMessageResultFilter.java | 45 ++------ .../grpc/v2/service/LocalGrpcServiceTest.java | 62 ----------- .../service/cluster/ConsumerServiceTest.java | 63 +---------- .../cluster/TransactionServiceTest.java | 7 +- .../test/grpc/v2/ClusterGrpcTest.java | 10 -- .../rocketmq/test/grpc/v2/GrpcBaseTest.java | 100 ----------------- .../rocketmq/test/grpc/v2/LocalGrpcTest.java | 10 -- 26 files changed, 181 insertions(+), 576 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/{ReceiveMessageResponseStreamWriter.java => BaseReceiveMessageResponseStreamWriter.java} (97%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index da49e56106..6243e3fdf4 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -21,7 +21,6 @@ import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; @@ -210,14 +209,6 @@ public class PlainAccessValidator implements AccessValidator { Resource topic = request.getTopic(); String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); accessResource.addResourceAndPerm(topicName, Permission.SUB); - } else if (NackMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - NackMessageRequest request = (NackMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); } else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) { ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3; Resource group = request.getGroup(); 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 2ed0d9d1cd..613fe0f589 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 @@ -56,6 +56,7 @@ public abstract class AbstractTransactionalMessageCheckListener { checkTransactionStateRequestHeader.setMsgId(msgExt.getUserProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX)); checkTransactionStateRequestHeader.setTransactionId(checkTransactionStateRequestHeader.getMsgId()); checkTransactionStateRequestHeader.setTranStateTableOffset(msgExt.getQueueOffset()); + checkTransactionStateRequestHeader.setBrokerName(brokerController.getBrokerConfig().getBrokerName()); msgExt.setTopic(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_TOPIC)); msgExt.setQueueId(Integer.parseInt(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_QUEUE_ID))); msgExt.setStoreSize(0); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java index 149de9b579..6671a9d773 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java @@ -25,6 +25,7 @@ import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class CheckTransactionStateRequestHeader implements CommandCustomHeader { + private String brokerName; @CFNotNull private Long tranStateTableOffset; @CFNotNull @@ -37,6 +38,14 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { public void checkFields() throws RemotingCommandException { } + public String getBrokerName() { + return brokerName; + } + + public void setBrokerName(String brokerName) { + this.brokerName = brokerName; + } + public Long getTranStateTableOffset() { return tranStateTableOffset; } @@ -80,7 +89,8 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { @Override public String toString() { return "CheckTransactionStateRequestHeader{" + - "tranStateTableOffset=" + tranStateTableOffset + + "brokerName='" + brokerName + '\'' + + ", tranStateTableOffset=" + tranStateTableOffset + ", commitLogOffset=" + commitLogOffset + ", msgId='" + msgId + '\'' + ", transactionId='" + transactionId + '\'' + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java index 41001e8f6e..3c03488916 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java @@ -68,6 +68,7 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { requestHeader.getTransactionId(), requestHeader.getCommitLogOffset(), requestHeader.getTranStateTableOffset()), + requestHeader.getBrokerName(), messageExt ) ); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java index ad6b5ac0d6..c5269e64f9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java @@ -24,6 +24,7 @@ public class TransactionStateCheckRequest { private Long commitLogOffset; private String msgId; private TransactionId transactionId; + private String brokerName; private MessageExt messageExt; public TransactionStateCheckRequest( @@ -32,6 +33,7 @@ public class TransactionStateCheckRequest { Long commitLogOffset, String msgId, TransactionId transactionId, + String brokerName, MessageExt messageExt ) { this.groupId = groupId; @@ -39,6 +41,7 @@ public class TransactionStateCheckRequest { this.commitLogOffset = commitLogOffset; this.msgId = msgId; this.transactionId = transactionId; + this.brokerName = brokerName; this.messageExt = messageExt; } @@ -82,6 +85,14 @@ public class TransactionStateCheckRequest { this.transactionId = transactionId; } + public String getBrokerName() { + return brokerName; + } + + public void setBrokerName(String brokerName) { + this.brokerName = brokerName; + } + public MessageExt getMessageExt() { return messageExt; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java index ad06e23074..89666c1a80 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java @@ -28,8 +28,6 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; import apache.rocketmq.v2.MessagingServiceGrpc; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.QueryAssignmentRequest; @@ -119,19 +117,6 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic grpcForwardService.receiveMessage(Context.current(), request, responseObserver); } - @Override - public void nackMessage(NackMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.nackMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - NackMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - } - @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java index 883abf6291..52fb47d950 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java @@ -26,7 +26,6 @@ import apache.rocketmq.v2.Digest; import apache.rocketmq.v2.DigestType; import apache.rocketmq.v2.Encoding; import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.ExponentialBackoff; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -34,12 +33,10 @@ import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; -import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.Permission; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.SubscriptionEntry; @@ -63,6 +60,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.constant.PermName; @@ -245,11 +243,6 @@ public class GrpcConverter { return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); } - public static AckMessageRequestHeader buildAckMessageRequestHeader(NackMessageRequest request) { - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); - } - public static AckMessageRequestHeader buildAckMessageRequestHeader(Resource topic, Resource group, ReceiptHandle handle) { String groupName = GrpcConverter.wrapResourceWithNamespace(group); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); @@ -263,37 +256,6 @@ public class GrpcConverter { return ackMessageRequestHeader; } - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(NackMessageRequest request, - RetryPolicy retryPolicy) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime( - Durations.toMillis(calculateNextDeliveryDurations(retryPolicy, request.getDeliveryAttempt()))); - return changeInvisibleTimeRequestHeader; - } - - public static Duration calculateNextDeliveryDurations(RetryPolicy retryPolicy, int deliveryAttempt) { - if (retryPolicy.hasCustomizedBackoff()) { - int nextCount = retryPolicy.getCustomizedBackoff().getNextCount(); - return retryPolicy.getCustomizedBackoff().getNext(Math.min(nextCount, deliveryAttempt)); - } - ExponentialBackoff exponentialBackoff = retryPolicy.getExponentialBackoff(); - long nextDurationMillis = (long) (Math.pow(exponentialBackoff.getMultiplier(), deliveryAttempt) * - Durations.toMillis(exponentialBackoff.getInitial())); - nextDurationMillis = Math.min( - Durations.toMillis(exponentialBackoff.getMax()), - nextDurationMillis); - return Durations.fromMillis(nextDurationMillis); - } - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); @@ -328,13 +290,6 @@ public class GrpcConverter { return buildConsumerSendMsgBackRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle, messageId, maxReconsumeTimes); } - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader( - NackMessageRequest request, int maxReconsumeTimes) { - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, - request.getMessageId(), maxReconsumeTimes); - } - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( ForwardMessageToDeadLetterQueueRequest request) { ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); @@ -494,6 +449,24 @@ public class GrpcConverter { return message; } + public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { + Broker broker = Broker.getDefaultInstance(); + if (!StringUtils.isEmpty(brokerName)) { + broker = Broker.newBuilder() + .setName(brokerName) + .setId(0) + .build(); + } + return MessageQueue.newBuilder() + .setId(messageExt.getQueueId()) + .setTopic(Resource.newBuilder() + .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) + .build()) + .setBroker(broker) + .build(); + } + public static String buildExpressionType(FilterType filterType) { switch (filterType) { case SQL: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java index eafca24f49..7f5ee2a13e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java @@ -22,7 +22,6 @@ import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.NackMessageRequest; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryRouteRequest; @@ -42,7 +41,6 @@ public class RequestMapping { put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); - put(NackMessageRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java index cd82c34d1b..a14dd4e3f8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java @@ -130,6 +130,7 @@ public class GrpcClientChannel extends SimpleChannel { .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(transactionId.getProxyTransactionId()) .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) + .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, header.getBrokerName())) .build()) .build()); break; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java index 32998280f2..1f1cadb746 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java @@ -30,19 +30,19 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; -public abstract class ReceiveMessageResponseStreamWriter { +public abstract class BaseReceiveMessageResponseStreamWriter { protected final StreamObserver streamObserver; protected final ResponseHook receiveMessageHook; protected final ReceiveMessageResultFilter receiveMessageResultFilter; public interface Builder { - ReceiveMessageResponseStreamWriter build( + BaseReceiveMessageResponseStreamWriter build( StreamObserver observer, ResponseHook hook); } - public ReceiveMessageResponseStreamWriter( + public BaseReceiveMessageResponseStreamWriter( StreamObserver observer, ResponseHook hook, ReceiveMessageResultFilter messageResultFilter) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java new file mode 100644 index 0000000000..350335f1fd --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.service; + +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Settings; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; +import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; + +public abstract class BaseReceiveMessageResultFilter implements ReceiveMessageResultFilter { + + protected final GrpcClientManager grpcClientManager; + + public BaseReceiveMessageResultFilter(GrpcClientManager manager) { + grpcClientManager = manager; + } + + @Override + public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { + if (messageExtList == null || messageExtList.isEmpty()) { + return Collections.emptyList(); + } + String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); + Settings settings = grpcClientManager.getClientSettings(ctx); + int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); + List resMessageList = new ArrayList<>(); + for (MessageExt messageExt : messageExtList) { + if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + processNoMatchMessage(ctx, request, messageExt); + continue; + } + if (messageExt.getReconsumeTimes() >= maxAttempts) { + processExceedMaxAttemptsMessage(ctx, request, messageExt, maxAttempts); + continue; + } + resMessageList.add(GrpcConverter.buildMessage(messageExt)); + } + return resMessageList; + } + + protected abstract void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt); + + protected abstract void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempts); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java index 6ebc350747..f47dcc9071 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java @@ -27,8 +27,6 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.QueryAssignmentRequest; @@ -130,11 +128,6 @@ public class ClusterGrpcService extends AbstractStartAndShutdown implements Grpc consumerService.receiveMessage(ctx, request, responseObserver); } - @Override - public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - return consumerService.nackMessage(ctx, request); - } - @Override public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { return consumerService.ackMessage(ctx, request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java index 48d2f2504f..3f0b459612 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java @@ -27,8 +27,6 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.QueryAssignmentRequest; @@ -57,8 +55,6 @@ public interface GrpcForwardService extends StartAndShutdown { void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver); - CompletableFuture nackMessage(Context ctx, NackMessageRequest request); - CompletableFuture ackMessage(Context ctx, AckMessageRequest request); CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 6cb84a5c4b..414c480343 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -30,8 +30,6 @@ import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.QueryAssignmentRequest; @@ -41,7 +39,6 @@ import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Settings; @@ -120,7 +117,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo private final RouteService routeService; private final ClientSettingsService clientSettingsService; private final LocalWriteQueueSelector localWriteQueueSelector; - private final ReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; + private final BaseReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; private volatile ResponseHook receiveMessageHook; @@ -271,7 +268,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); // TODO: get fifo config from subscriptionGroupManager boolean fifo = false; - ReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); + BaseReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); ReceiveMessageChannel channel = channelManager.createChannel(ctx, context -> new ReceiveMessageChannel(context, handler), ReceiveMessageChannel.class); CompletableFuture> future = new CompletableFuture<>(); @@ -345,50 +342,6 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo return future; } - @Override - public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture future = new CompletableFuture<>(); - - RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getBackoffPolicy(); - int maxReconsumeTimes = retryPolicy.getMaxAttempts(); - if (request.getDeliveryAttempt() >= maxReconsumeTimes) { - ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); - command.makeCustomHeaderToNet(); - - try { - RemotingCommand responseCommand = brokerController.getSendMessageProcessor() - .processRequest(channelHandlerContext, command); - NackMessageResponse response = NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .build(); - future.complete(response); - } catch (Exception e) { - log.error("Exception raised while nackMessage", e); - future.completeExceptionally(e); - } - } else { - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, retryPolicy); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); - command.makeCustomHeaderToNet(); - - try { - RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() - .processRequest(channelHandlerContext, command); - NackMessageResponse response = NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .build(); - future.complete(response); - } catch (Exception e) { - log.error("Exception raised while nackMessage", e); - future.completeExceptionally(e); - } - } - return future; - } - @Override public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java index 8df9fd14f7..474ed29f15 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java @@ -23,12 +23,8 @@ import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.RetryPolicy; -import apache.rocketmq.v2.Settings; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.ArrayList; @@ -39,7 +35,6 @@ import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.connector.ConnectorManager; import org.apache.rocketmq.proxy.connector.ForwardProducer; @@ -52,8 +47,7 @@ import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; public class ConsumerService extends BaseService { protected final ForwardReadConsumer readConsumer; @@ -65,11 +59,10 @@ public class ConsumerService extends BaseService { protected final GrpcClientManager grpcClientManager; private volatile ReadQueueSelector readQueueSelector; - private volatile ReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; + private volatile BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; private volatile ResponseHook receiveMessageHook; private volatile ResponseHook ackMessageHook; - private volatile ResponseHook nackMessageHook; private volatile ResponseHook changeInvisibleDurationHook; public ConsumerService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { @@ -92,7 +85,7 @@ public class ConsumerService extends BaseService { public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - ReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); + BaseReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); try { PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); @@ -203,72 +196,6 @@ public class ConsumerService extends BaseService { .build(); } - public CompletableFuture nackMessage(Context ctx, NackMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); - try { - ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); - String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - - Settings settings = grpcClientManager.getClientSettings(ctx); - int maxDeliveryAttempts = settings.getBackoffPolicy().getMaxAttempts(); - if (request.getDeliveryAttempt() >= maxDeliveryAttempts) { - future = this.producer.sendMessageBackThenAckOrg( - ctx, - brokerAddr, - this.buildConsumerSendMsgBackToDLQRequestHeader(ctx, request, maxDeliveryAttempts), - this.buildAckMessageRequestHeader(ctx, request) - ).thenApply(result -> convertToNackMessageResponse(ctx, request, result)); - } else { - ChangeInvisibleTimeRequestHeader requestHeader = this.buildChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), request.getMessageId(), requestHeader) - .thenApply(result -> convertToNackMessageResponse(ctx, request, result)); - } - } catch (Throwable t) { - future.completeExceptionally(t); - } - future.whenComplete((response, throwable) -> { - if (nackMessageHook != null) { - nackMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); - return future; - } - - protected ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(Context ctx, - NackMessageRequest request) { - RetryPolicy retryPolicy = grpcClientManager.getClientSettings(ctx).getBackoffPolicy(); - return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, retryPolicy); - } - - protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, NackMessageRequest request) { - return GrpcConverter.buildAckMessageRequestHeader(request); - } - - protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackToDLQRequestHeader(Context ctx, - NackMessageRequest request, - int maxReconsumeTimes) { - return GrpcConverter.buildConsumerSendMsgBackToDLQRequestHeader(request, maxReconsumeTimes); - } - - protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, - AckResult ackResult) { - if (AckStatus.OK.equals(ackResult.getStatus())) { - return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); - } - return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "nack failed: status is abnormal")) - .build(); - } - - protected NackMessageResponse convertToNackMessageResponse(Context ctx, NackMessageRequest request, - RemotingCommand sendMsgBackToDLQResult) { - return NackMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(sendMsgBackToDLQResult.getCode(), sendMsgBackToDLQResult.getRemark())) - .build(); - } - public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { CompletableFuture future = new CompletableFuture<>(); @@ -318,12 +245,12 @@ public class ConsumerService extends BaseService { this.readQueueSelector = readQueueSelector; } - public ReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { + public BaseReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { return receiveMessageWriterBuilder; } public void setReceiveMessageWriterBuilder( - ReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { + BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { this.receiveMessageWriterBuilder = receiveMessageWriterBuilder; } @@ -345,15 +272,6 @@ public class ConsumerService extends BaseService { this.ackMessageHook = ackMessageHook; } - public ResponseHook getNackMessageHook() { - return nackMessageHook; - } - - public void setNackMessageHook( - ResponseHook nackMessageHook) { - this.nackMessageHook = nackMessageHook; - } - public ResponseHook getChangeInvisibleDurationHook() { return changeInvisibleDurationHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java index bf071719f3..10dfda6fcc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -33,10 +33,10 @@ import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -public class DefaultReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { +public class DefaultReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java index b15951eb74..adf662e87b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -17,38 +17,29 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; -import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; import io.grpc.Context; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.connector.ForwardProducer; import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; -public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFilter { +public class DefaultReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { protected final ForwardProducer producer; protected final ForwardWriteConsumer writeConsumer; - protected final GrpcClientManager grpcClientManager; protected final TopicRouteCache topicRouteCache; private volatile ResponseHook ackNoMatchedMessageHook; @@ -56,69 +47,14 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi public DefaultReceiveMessageResultFilter(ForwardProducer producer, ForwardWriteConsumer writeConsumer, GrpcClientManager grpcClientManager, TopicRouteCache topicRouteCache) { + super(grpcClientManager); this.producer = producer; this.writeConsumer = writeConsumer; - this.grpcClientManager = grpcClientManager; this.topicRouteCache = topicRouteCache; } @Override - public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { - if (messageExtList == null || messageExtList.isEmpty()) { - return Collections.emptyList(); - } - Settings settings = grpcClientManager.getClientSettings(ctx); - int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); - Resource topic = request.getMessageQueue().getTopic(); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); - - List resMessageList = new ArrayList<>(); - for (MessageExt messageExt : messageExtList) { - if (messageExt.getReconsumeTimes() >= maxAttempts) { - forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); - continue; - } - if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { - this.ackNoMatchedMessage(ctx, request, messageExt); - continue; - } - resMessageList.add(GrpcConverter.buildMessage(messageExt)); - } - return resMessageList; - } - - protected void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, - int maxReconsumeTimes) { - CompletableFuture future = new CompletableFuture<>(); - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - - try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( - request, - handle, - messageExt.getMsgId(), - maxReconsumeTimes); - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); - - future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((result, throwable) -> { - if (forwardToDLQInRecvMessageHook != null) { - forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); - } - }); - } - - protected void ackNoMatchedMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { + protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { CompletableFuture future = new CompletableFuture<>(); ReceiptHandle handle = ReceiptHandle.create(messageExt); @@ -140,6 +76,37 @@ public class DefaultReceiveMessageResultFilter implements ReceiveMessageResultFi }); } + @Override + protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, + int maxAttempts) { + CompletableFuture future = new CompletableFuture<>(); + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + + try { + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); + ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( + request, + handle, + messageExt.getMsgId(), + maxAttempts); + AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); + + future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); + } catch (Throwable t) { + future.completeExceptionally(t); + } + + future.whenComplete((result, throwable) -> { + if (forwardToDLQInRecvMessageHook != null) { + forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); + } + }); + } + public ResponseHook getAckNoMatchedMessageHook() { return ackNoMatchedMessageHook; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java index d142e2de98..9600d7acc2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; import org.apache.commons.collections.CollectionUtils; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.ConnectorManager; @@ -68,12 +69,14 @@ public class TransactionService extends BaseService implements TransactionStateC GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); String transactionId = checkData.getTransactionId().getProxyTransactionId(); - Message message = GrpcConverter.buildMessage(checkData.getMessageExt()); + MessageExt messageExt = checkData.getMessageExt(); + Message message = GrpcConverter.buildMessage(messageExt); TelemetryCommand response = TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand( RecoverOrphanedTransactionCommand.newBuilder() .setOrphanedTransactionalMessage(message) .setTransactionId(transactionId) + .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, checkData.getBrokerName())) .build() ).build(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java index 50fe0e1a59..0ec9913e22 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java @@ -32,14 +32,14 @@ import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResponseStreamWriter; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalReceiveMessageResponseStreamWriter extends ReceiveMessageResponseStreamWriter { +public class LocalReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ChannelManager channelManager; private final BrokerController brokerController; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java index 62ea8fb78c..c69aab2567 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java @@ -17,14 +17,9 @@ package org.apache.rocketmq.proxy.grpc.v2.service.local; -import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Settings; import io.grpc.Context; import io.netty.channel.Channel; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; @@ -33,56 +28,30 @@ import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LocalReceiveMessageResultFilter implements ReceiveMessageResultFilter { +public class LocalReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ChannelManager channelManager; private final BrokerController brokerController; - private final GrpcClientManager grpcClientManager; public LocalReceiveMessageResultFilter(ChannelManager channelManager, BrokerController brokerController, GrpcClientManager grpcClientManager) { + super(grpcClientManager); this.channelManager = channelManager; this.brokerController = brokerController; - this.grpcClientManager = grpcClientManager; } @Override - public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { - if (messageExtList == null || messageExtList.isEmpty()) { - return Collections.emptyList(); - } - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); - Settings settings = grpcClientManager.getClientSettings(ctx); - int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); - List resMessageList = new ArrayList<>(); - for (MessageExt messageExt : messageExtList) { - if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { - ackMessage(ctx, request, messageExt); - continue; - } - if (messageExt.getReconsumeTimes() >= maxAttempts) { - forwardMessageToDLQ(ctx, request, messageExt, maxAttempts); - continue; - } - resMessageList.add(GrpcConverter.buildMessage(messageExt)); - } - return resMessageList; - } - - private void ackMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { + protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { ReceiptHandle handle = ReceiptHandle.create(messageExt); if (handle == null) { return; @@ -98,7 +67,9 @@ public class LocalReceiveMessageResultFilter implements ReceiveMessageResultFilt } } - private void forwardMessageToDLQ(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempt) { + @Override + protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, + int maxAttempts) { try { ReceiptHandle handle = ReceiptHandle.create(messageExt); if (handle == null) { @@ -106,7 +77,7 @@ public class LocalReceiveMessageResultFilter implements ReceiveMessageResultFilt } Channel channel = channelManager.createChannel(ctx); SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempt); + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempts); RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, consumerSendMsgBackRequestHeader); command.makeCustomHeaderToNet(); RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, command); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java index dc07124b75..13a87b25d1 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -32,8 +32,6 @@ import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.ReceiveMessageRequest; @@ -379,66 +377,6 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); } - @Test - public void testNackMessage() throws Exception { - ChangeInvisibleTimeResponseHeader responseHeader = new ChangeInvisibleTimeResponseHeader(); - responseHeader.setInvisibleTime(1000L); - responseHeader.setPopTime(0L); - responseHeader.setReviveQid(0); - RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); - - ChangeInvisibleTimeProcessor changeInvisibleTimeProcessor = Mockito.mock(ChangeInvisibleTimeProcessor.class); - Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessor); - Mockito.when(changeInvisibleTimeProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - NackMessageRequest request = NackMessageRequest.newBuilder().setReceiptHandle( - ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode() - ).build(); - CompletableFuture grpcFuture = localGrpcService.nackMessage(Context.current(), request); - NackMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - } - - @Test - public void testNackMessageWhenDLQ() throws Exception { - ConsumerSendMsgBackRequestHeader responseHeader = new ConsumerSendMsgBackRequestHeader(); - RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); - - SendMessageProcessor sendMessageProcessor = Mockito.mock(SendMessageProcessor.class); - Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessor); - Mockito.when(sendMessageProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - NackMessageRequest request = NackMessageRequest.newBuilder() - .setDeliveryAttempt(3) - .setReceiptHandle( - ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode() - ).build(); - CompletableFuture grpcFuture = localGrpcService.nackMessage( - Context.current(), request); - NackMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - } - @Test public void testForwardMessageToDeadLetterQueue() throws Exception { RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index 7857f207d2..b8d045dc8c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -25,8 +25,6 @@ import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.FilterType; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; @@ -175,6 +173,8 @@ public class ConsumerServiceTest extends BaseServiceTest { ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), sendMsgBackRequestHeaderArgumentCaptor.capture(), any())) .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); + when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())) + .thenReturn(CompletableFuture.completedFuture(new AckResult())); Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); consumerService.receiveMessage(ctx, @@ -187,7 +187,7 @@ public class ConsumerServiceTest extends BaseServiceTest { .build()) .setFilterExpression(FilterExpression.newBuilder() .setType(FilterType.TAG) - .setExpression("msg1") + .setExpression("*") .build()) .build(), receiveMessageResponseStreamObserver @@ -228,63 +228,6 @@ public class ConsumerServiceTest extends BaseServiceTest { assertEquals(Code.OK, response.getStatus().getCode()); } - @Test - public void testNackMessageToDLQ() throws Exception { - ReceiptHandle receiptHandle = createReceiptHandle(); - ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); - when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), headerArgumentCaptor.capture(), any())) - .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - - Settings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - - NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .setReceiptHandle(receiptHandle.encode()) - .setDeliveryAttempt(3) - .build()) - .get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(receiptHandle.getCommitLogOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); - } - - @Test - public void testNackMessage() throws Exception { - ReceiptHandle receiptHandle = createReceiptHandle(); - ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); - AckResult ackResult = new AckResult(); - ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), anyString(), headerArgumentCaptor.capture())) - .thenReturn(CompletableFuture.completedFuture(ackResult)); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - - Settings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - - NackMessageResponse response = consumerService.nackMessage(Context.current(), NackMessageRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .setReceiptHandle(receiptHandle.encode()) - .setDeliveryAttempt(1) - .build()) - .get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(receiptHandle.getOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); - assertEquals(receiptHandle.encode(), headerArgumentCaptor.getValue().getExtraInfo()); - } - @Test public void testChangeInvisibleDuration() throws Exception { Duration newDuration = Duration.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java index 5c762e3f12..eafc3a4325 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -19,8 +19,10 @@ package org.apache.rocketmq.proxy.grpc.v2.service.cluster; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.channel.ChannelManager; import org.apache.rocketmq.proxy.connector.transaction.TransactionId; @@ -69,13 +71,16 @@ public class TransactionServiceTest extends BaseServiceTest { 2L, "msgId", transactionId, + "brokerName", createMessageExt("msgId", "msgId") )); Object flushData = flushDataCaptor.getValue(); assertTrue(flushData instanceof TelemetryCommand); TelemetryCommand response = (TelemetryCommand) flushData; - assertEquals(transactionId.getProxyTransactionId(), response.getRecoverOrphanedTransactionCommand().getTransactionId()); + RecoverOrphanedTransactionCommand command = response.getRecoverOrphanedTransactionCommand(); + assertEquals(transactionId.getProxyTransactionId(), command.getTransactionId()); + assertEquals("brokerName", command.getMessageQueue().getBroker().getName()); } @Test diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java index 431b236f83..82e6dc659c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java @@ -76,21 +76,11 @@ public class ClusterGrpcTest extends GrpcBaseTest { assertQueryAssignment(response, brokerNum); } - @Test - public void testSendReceiveMessage() throws Exception { - super.testSendReceiveMessage(); - } - @Test public void testTransactionCheckThenCommit() { super.testTransactionCheckThenCommit(); } - @Test - public void testSendReceiveMessageThenToDLQ() throws Exception { - super.testSendReceiveMessageThenToDLQ(); - } - @Test public void testSimpleConsumerSendAndRecv() throws Exception { super.testSimpleConsumerSendAndRecv(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java index b008ead8d0..a1a93620ba 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java @@ -35,8 +35,6 @@ import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.MessagingServiceGrpc; -import apache.rocketmq.v2.NackMessageRequest; -import apache.rocketmq.v2.NackMessageResponse; import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.QueryAssignmentRequest; import apache.rocketmq.v2.QueryAssignmentResponse; @@ -208,84 +206,6 @@ public class GrpcBaseTest extends BaseConf { .build()); } - public void testSendReceiveMessage() throws Exception { - String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = MQRandomUtils.getRandomConsumerGroup(); - - // init consumer offset - this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - receiveMessage(blockingStub, topic, group, 1); - - String messageId = createUniqID(); - this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); - assertSendMessage(sendResponse, messageId); - - this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - - Message responseMessage = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); - String receiptHandle = responseMessage.getSystemProperties().getReceiptHandle(); - AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, messageId, receiptHandle)); - assertAllAckOk(ackMessageResponse); - } - - public void testSendReceiveMessageThenToDLQ() throws Exception { - String topic = initTopicOnSampleTopicBroker(broker1Name); - String group = MQRandomUtils.getRandomConsumerGroup(); - - // init consumer offset - this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - receiveMessage(blockingStub, topic, group, 1); - - this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); - String messageId = createUniqID(); - SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); - assertSendMessage(sendResponse, messageId); - - this.sendClientSettings(stub, buildPushConsumerClientSettings()).get(); - - Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); - - NackMessageResponse nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 1 - )); - assertNackMessageResponse(nackMessageResponse); - - AtomicReference receiveRetryMessageRef = new AtomicReference<>(); - await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { - List messageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group, 1)); - if (messageList.isEmpty()) { - return false; - } - - receiveRetryMessageRef.set(messageList.get(0)); - return messageList.get(0).getSystemProperties() - .getMessageId().equals(messageId); - }); - - message = receiveRetryMessageRef.get(); - nackMessageResponse = blockingStub.nackMessage(buildNackMessageRequest( - topic, group, messageId, message.getSystemProperties().getReceiptHandle(), 2 - )); - assertNackMessageResponse(nackMessageResponse); - - DefaultMQPullConsumer defaultMQPullConsumer = new DefaultMQPullConsumer(group); - defaultMQPullConsumer.start(); - org.apache.rocketmq.common.message.MessageQueue dlqMQ = new org.apache.rocketmq.common.message.MessageQueue(MixAll.getDLQTopic(group), broker1Name, 0); - await().atMost(java.time.Duration.ofSeconds(10)).until(() -> { - try { - PullResult pullResult = defaultMQPullConsumer.pull(dlqMQ, "*", 0L, 1); - if (!PullStatus.FOUND.equals(pullResult.getPullStatus())) { - return false; - } - MessageExt messageExt = pullResult.getMsgFoundList().get(0); - return messageId.equals(messageExt.getMsgId()); - } catch (Throwable ignore) { - return false; - } - }); - } - public void testTransactionCheckThenCommit() { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); @@ -590,22 +510,6 @@ public class GrpcBaseTest extends BaseConf { .build(); } - public NackMessageRequest buildNackMessageRequest(String topic, String group, String messageId, - String receiptHandle, - int deliveryAttempt) { - return NackMessageRequest.newBuilder() - .setDeliveryAttempt(deliveryAttempt) - .setMessageId(messageId) - .setReceiptHandle(receiptHandle) - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .setGroup(Resource.newBuilder() - .setName(group) - .build()) - .build(); - } - public EndTransactionRequest buildEndTransactionRequest(String topic, String messageId, String transactionId, TransactionResolution resolution) { return EndTransactionRequest.newBuilder() @@ -666,10 +570,6 @@ public class GrpcBaseTest extends BaseConf { } } - public void assertNackMessageResponse(NackMessageResponse response) { - assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); - } - public void assertRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand command, String messageId) { assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) .isEqualTo(messageId); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java index d28f4311fd..d99b28ea99 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java @@ -62,21 +62,11 @@ public class LocalGrpcTest extends GrpcBaseTest { assertQueryAssignment(response, brokerNum); } - @Test - public void testSendReceiveMessage() throws Exception { - super.testSendReceiveMessage(); - } - @Test public void testTransactionCheckThenCommit() { super.testTransactionCheckThenCommit(); } - @Test - public void testSendReceiveMessageThenToDLQ() throws Exception { - super.testSendReceiveMessageThenToDLQ(); - } - @Test public void testSimpleConsumerSendAndRecv() throws Exception { super.testSimpleConsumerSendAndRecv(); From c6d6853ec3cd5549a26b1d1171a40b4d8d7feee5 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 6 May 2022 15:54:15 +0800 Subject: [PATCH 164/338] [ISSUE #3949] Move parse and build method to PlainAccessResource --- .../acl/plain/PlainAccessResource.java | 212 ++++++++++++++++++ .../acl/plain/PlainAccessValidator.java | 189 +--------------- .../acl/plain/PlainPermissionManager.java | 19 +- 3 files changed, 216 insertions(+), 204 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java index a0cceed8c3..a879360bb4 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java @@ -16,11 +16,42 @@ */ package org.apache.rocketmq.acl.plain; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import com.google.protobuf.GeneratedMessageV3; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import org.apache.commons.codec.DecoderException; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.rocketmq.acl.AccessResource; +import org.apache.rocketmq.acl.common.AclException; +import org.apache.rocketmq.acl.common.AclUtils; +import org.apache.rocketmq.acl.common.AuthorizationHeader; +import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.common.Permission; +import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.PlainAccessConfig; +import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; +import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class PlainAccessResource implements AccessResource { @@ -55,6 +86,187 @@ public class PlainAccessResource implements AccessResource { public PlainAccessResource() { } + public static PlainAccessResource parse(RemotingCommand request, String remoteAddr) { + PlainAccessResource accessResource = new PlainAccessResource(); + if (remoteAddr != null && remoteAddr.contains(":")) { + accessResource.setWhiteRemoteAddress(remoteAddr.substring(0, remoteAddr.lastIndexOf(':'))); + } else { + accessResource.setWhiteRemoteAddress(remoteAddr); + } + + accessResource.setRequestCode(request.getCode()); + + if (request.getExtFields() == null) { + // If request's extFields is null,then return accessResource directly(users can use whiteAddress pattern) + // The following logic codes depend on the request's extFields not to be null. + return accessResource; + } + accessResource.setAccessKey(request.getExtFields().get(SessionCredentials.ACCESS_KEY)); + accessResource.setSignature(request.getExtFields().get(SessionCredentials.SIGNATURE)); + accessResource.setSecretToken(request.getExtFields().get(SessionCredentials.SECURITY_TOKEN)); + + try { + switch (request.getCode()) { + case RequestCode.SEND_MESSAGE: + accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.PUB); + break; + case RequestCode.SEND_MESSAGE_V2: + accessResource.addResourceAndPerm(request.getExtFields().get("b"), Permission.PUB); + break; + case RequestCode.CONSUMER_SEND_MSG_BACK: + accessResource.addResourceAndPerm(request.getExtFields().get("originTopic"), Permission.PUB); + accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("group")), Permission.SUB); + break; + case RequestCode.PULL_MESSAGE: + accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB); + accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("consumerGroup")), Permission.SUB); + break; + case RequestCode.QUERY_MESSAGE: + accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB); + break; + case RequestCode.HEART_BEAT: + HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class); + for (ConsumerData data : heartbeatData.getConsumerDataSet()) { + accessResource.addResourceAndPerm(getRetryTopic(data.getGroupName()), Permission.SUB); + for (SubscriptionData subscriptionData : data.getSubscriptionDataSet()) { + accessResource.addResourceAndPerm(subscriptionData.getTopic(), Permission.SUB); + } + } + break; + case RequestCode.UNREGISTER_CLIENT: + final UnregisterClientRequestHeader unregisterClientRequestHeader = + (UnregisterClientRequestHeader) request + .decodeCommandCustomHeader(UnregisterClientRequestHeader.class); + accessResource.addResourceAndPerm(getRetryTopic(unregisterClientRequestHeader.getConsumerGroup()), Permission.SUB); + break; + case RequestCode.GET_CONSUMER_LIST_BY_GROUP: + final GetConsumerListByGroupRequestHeader getConsumerListByGroupRequestHeader = + (GetConsumerListByGroupRequestHeader) request + .decodeCommandCustomHeader(GetConsumerListByGroupRequestHeader.class); + accessResource.addResourceAndPerm(getRetryTopic(getConsumerListByGroupRequestHeader.getConsumerGroup()), Permission.SUB); + break; + case RequestCode.UPDATE_CONSUMER_OFFSET: + final UpdateConsumerOffsetRequestHeader updateConsumerOffsetRequestHeader = + (UpdateConsumerOffsetRequestHeader) request + .decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class); + accessResource.addResourceAndPerm(getRetryTopic(updateConsumerOffsetRequestHeader.getConsumerGroup()), Permission.SUB); + accessResource.addResourceAndPerm(updateConsumerOffsetRequestHeader.getTopic(), Permission.SUB); + break; + default: + break; + + } + } catch (Throwable t) { + throw new AclException(t.getMessage(), t); + } + + // Content + SortedMap map = new TreeMap(); + for (Map.Entry entry : request.getExtFields().entrySet()) { + if (!SessionCredentials.SIGNATURE.equals(entry.getKey()) + && !MixAll.UNIQUE_MSG_QUERY_FLAG.equals(entry.getKey())) { + map.put(entry.getKey(), entry.getValue()); + } + } + accessResource.setContent(AclUtils.combineRequestContent(request, map)); + return accessResource; + } + + public static PlainAccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header) { + PlainAccessResource accessResource = new PlainAccessResource(); + String remoteAddress = header.getRemoteAddress(); + if (remoteAddress != null && remoteAddress.contains(":")) { + accessResource.setWhiteRemoteAddress(RemotingHelper.parseHostFromAddress(remoteAddress)); + } else { + accessResource.setWhiteRemoteAddress(remoteAddress); + } + try { + AuthorizationHeader authorizationHeader = new AuthorizationHeader(header.getAuthorization()); + accessResource.setAccessKey(authorizationHeader.getAccessKey()); + accessResource.setSignature(authorizationHeader.getSignature()); + } catch (DecoderException e) { + throw new AclException(e.getMessage(), e); + } + accessResource.setSecretToken(header.getSessionToken()); + accessResource.setRequestCode(header.getRequestCode()); + accessResource.setContent(header.getDatetime().getBytes(StandardCharsets.UTF_8)); + + try { + String rpcFullName = messageV3.getDescriptorForType().getFullName(); + if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { + HeartbeatRequest request = (HeartbeatRequest) messageV3; + if (request.hasGroup()) { + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + } + } else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + SendMessageRequest request = (SendMessageRequest) messageV3; + if (request.getMessagesCount() <= 0) { + throw new AclException("SendMessageRequest, messageCount is zero", ResponseCode.MESSAGE_ILLEGAL); + } + Resource topic = request.getMessages(0).getTopic(); + for (Message message : request.getMessagesList()) { + if (!message.getTopic().equals(topic)) { + throw new AclException("SendMessageRequest, messages' topic is not consistent", ResponseCode.MESSAGE_ILLEGAL); + } + } + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.PUB); + } else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + ReceiveMessageRequest request = (ReceiveMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getMessageQueue().getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { + AckMessageRequest request = (AckMessageRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) { + ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3; + Resource group = request.getGroup(); + String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); + accessResource.addResourceAndPerm(groupName, Permission.SUB); + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.SUB); + } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { + EndTransactionRequest request = (EndTransactionRequest) messageV3; + Resource topic = request.getTopic(); + String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); + accessResource.addResourceAndPerm(topicName, Permission.PUB); + } + } catch (Throwable t) { + throw new AclException(t.getMessage(), t); + } + return accessResource; + } + + public static PlainAccessResource build(PlainAccessConfig plainAccessConfig, RemoteAddressStrategy remoteAddressStrategy) { + PlainAccessResource plainAccessResource = new PlainAccessResource(); + plainAccessResource.setAccessKey(plainAccessConfig.getAccessKey()); + plainAccessResource.setSecretKey(plainAccessConfig.getSecretKey()); + plainAccessResource.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress()); + + plainAccessResource.setAdmin(plainAccessConfig.isAdmin()); + + plainAccessResource.setDefaultGroupPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultGroupPerm())); + plainAccessResource.setDefaultTopicPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultTopicPerm())); + + Permission.parseResourcePerms(plainAccessResource, false, plainAccessConfig.getGroupPerms()); + Permission.parseResourcePerms(plainAccessResource, true, plainAccessConfig.getTopicPerms()); + + plainAccessResource.setRemoteAddressStrategy(remoteAddressStrategy); + return plainAccessResource; + } + public static boolean isRetryTopic(String topic) { return null != topic && topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX); } diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index 6243e3fdf4..99c2bd5699 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -16,47 +16,17 @@ */ package org.apache.rocketmq.acl.plain; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; import com.google.protobuf.GeneratedMessageV3; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; -import org.apache.commons.codec.DecoderException; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; -import org.apache.rocketmq.acl.common.AclException; -import org.apache.rocketmq.acl.common.AclUtils; -import org.apache.rocketmq.acl.common.AuthorizationHeader; import org.apache.rocketmq.acl.common.MetadataHeader; -import org.apache.rocketmq.acl.common.Permission; -import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.common.AclConfig; import org.apache.rocketmq.common.DataVersion; -import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.PlainAccessConfig; -import org.apache.rocketmq.common.protocol.NamespaceUtil; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; -import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData; -import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import static org.apache.rocketmq.acl.plain.PlainAccessResource.getRetryTopic; - public class PlainAccessValidator implements AccessValidator { private PlainPermissionManager aclPlugEngine; @@ -67,166 +37,11 @@ public class PlainAccessValidator implements AccessValidator { @Override public AccessResource parse(RemotingCommand request, String remoteAddr) { - PlainAccessResource accessResource = new PlainAccessResource(); - if (remoteAddr != null && remoteAddr.contains(":")) { - accessResource.setWhiteRemoteAddress(remoteAddr.substring(0, remoteAddr.lastIndexOf(':'))); - } else { - accessResource.setWhiteRemoteAddress(remoteAddr); - } - - accessResource.setRequestCode(request.getCode()); - - if (request.getExtFields() == null) { - // If request's extFields is null,then return accessResource directly(users can use whiteAddress pattern) - // The following logic codes depend on the request's extFields not to be null. - return accessResource; - } - accessResource.setAccessKey(request.getExtFields().get(SessionCredentials.ACCESS_KEY)); - accessResource.setSignature(request.getExtFields().get(SessionCredentials.SIGNATURE)); - accessResource.setSecretToken(request.getExtFields().get(SessionCredentials.SECURITY_TOKEN)); - - try { - switch (request.getCode()) { - case RequestCode.SEND_MESSAGE: - accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.PUB); - break; - case RequestCode.SEND_MESSAGE_V2: - accessResource.addResourceAndPerm(request.getExtFields().get("b"), Permission.PUB); - break; - case RequestCode.CONSUMER_SEND_MSG_BACK: - accessResource.addResourceAndPerm(request.getExtFields().get("originTopic"), Permission.PUB); - accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("group")), Permission.SUB); - break; - case RequestCode.PULL_MESSAGE: - accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB); - accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("consumerGroup")), Permission.SUB); - break; - case RequestCode.QUERY_MESSAGE: - accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB); - break; - case RequestCode.HEART_BEAT: - HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class); - for (ConsumerData data : heartbeatData.getConsumerDataSet()) { - accessResource.addResourceAndPerm(getRetryTopic(data.getGroupName()), Permission.SUB); - for (SubscriptionData subscriptionData : data.getSubscriptionDataSet()) { - accessResource.addResourceAndPerm(subscriptionData.getTopic(), Permission.SUB); - } - } - break; - case RequestCode.UNREGISTER_CLIENT: - final UnregisterClientRequestHeader unregisterClientRequestHeader = - (UnregisterClientRequestHeader) request - .decodeCommandCustomHeader(UnregisterClientRequestHeader.class); - accessResource.addResourceAndPerm(getRetryTopic(unregisterClientRequestHeader.getConsumerGroup()), Permission.SUB); - break; - case RequestCode.GET_CONSUMER_LIST_BY_GROUP: - final GetConsumerListByGroupRequestHeader getConsumerListByGroupRequestHeader = - (GetConsumerListByGroupRequestHeader) request - .decodeCommandCustomHeader(GetConsumerListByGroupRequestHeader.class); - accessResource.addResourceAndPerm(getRetryTopic(getConsumerListByGroupRequestHeader.getConsumerGroup()), Permission.SUB); - break; - case RequestCode.UPDATE_CONSUMER_OFFSET: - final UpdateConsumerOffsetRequestHeader updateConsumerOffsetRequestHeader = - (UpdateConsumerOffsetRequestHeader) request - .decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class); - accessResource.addResourceAndPerm(getRetryTopic(updateConsumerOffsetRequestHeader.getConsumerGroup()), Permission.SUB); - accessResource.addResourceAndPerm(updateConsumerOffsetRequestHeader.getTopic(), Permission.SUB); - break; - default: - break; - - } - } catch (Throwable t) { - throw new AclException(t.getMessage(), t); - } - - // Content - SortedMap map = new TreeMap(); - for (Map.Entry entry : request.getExtFields().entrySet()) { - if (!SessionCredentials.SIGNATURE.equals(entry.getKey()) - && !MixAll.UNIQUE_MSG_QUERY_FLAG.equals(entry.getKey())) { - map.put(entry.getKey(), entry.getValue()); - } - } - accessResource.setContent(AclUtils.combineRequestContent(request, map)); - return accessResource; + return PlainAccessResource.parse(request, remoteAddr); } @Override public AccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header) { - PlainAccessResource accessResource = new PlainAccessResource(); - String remoteAddress = header.getRemoteAddress(); - if (remoteAddress != null && remoteAddress.contains(":")) { - accessResource.setWhiteRemoteAddress(RemotingHelper.parseHostFromAddress(remoteAddress)); - } else { - accessResource.setWhiteRemoteAddress(remoteAddress); - } - try { - AuthorizationHeader authorizationHeader = new AuthorizationHeader(header.getAuthorization()); - accessResource.setAccessKey(authorizationHeader.getAccessKey()); - accessResource.setSignature(authorizationHeader.getSignature()); - } catch (DecoderException e) { - throw new AclException(e.getMessage(), e); - } - accessResource.setSecretToken(header.getSessionToken()); - accessResource.setRequestCode(header.getRequestCode()); - accessResource.setContent(header.getDatetime().getBytes(StandardCharsets.UTF_8)); - - try { - String rpcFullName = messageV3.getDescriptorForType().getFullName(); - if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { - HeartbeatRequest request = (HeartbeatRequest) messageV3; - if (request.hasGroup()) { - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - } - } else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - SendMessageRequest request = (SendMessageRequest) messageV3; - if (request.getMessagesCount() <= 0) { - throw new AclException("SendMessageRequest, messageCount is zero", ResponseCode.MESSAGE_ILLEGAL); - } - Resource topic = request.getMessages(0).getTopic(); - for (Message message : request.getMessagesList()) { - if (!message.getTopic().equals(topic)) { - throw new AclException("SendMessageRequest, messages' topic is not consistent", ResponseCode.MESSAGE_ILLEGAL); - } - } - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.PUB); - } else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - ReceiveMessageRequest request = (ReceiveMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getMessageQueue().getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); - } else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { - AckMessageRequest request = (AckMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); - } else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) { - ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); - } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { - EndTransactionRequest request = (EndTransactionRequest) messageV3; - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.PUB); - } - } catch (Throwable t) { - throw new AclException(t.getMessage(), t); - } - return accessResource; + return PlainAccessResource.parse(messageV3, header); } @Override diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java index 7fb9f0e4ca..d29a9dd853 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java @@ -614,23 +614,8 @@ public class PlainPermissionManager { public PlainAccessResource buildPlainAccessResource(PlainAccessConfig plainAccessConfig) throws AclException { checkPlainAccessConfig(plainAccessConfig); - PlainAccessResource plainAccessResource = new PlainAccessResource(); - plainAccessResource.setAccessKey(plainAccessConfig.getAccessKey()); - plainAccessResource.setSecretKey(plainAccessConfig.getSecretKey()); - plainAccessResource.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress()); - - plainAccessResource.setAdmin(plainAccessConfig.isAdmin()); - - plainAccessResource.setDefaultGroupPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultGroupPerm())); - plainAccessResource.setDefaultTopicPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultTopicPerm())); - - Permission.parseResourcePerms(plainAccessResource, false, plainAccessConfig.getGroupPerms()); - Permission.parseResourcePerms(plainAccessResource, true, plainAccessConfig.getTopicPerms()); - - plainAccessResource.setRemoteAddressStrategy(remoteAddressStrategyFactory. - getRemoteAddressStrategy(plainAccessResource.getWhiteRemoteAddress())); - - return plainAccessResource; + return PlainAccessResource.build(plainAccessConfig, remoteAddressStrategyFactory. + getRemoteAddressStrategy(plainAccessConfig.getWhiteRemoteAddress())); } public void validate(PlainAccessResource plainAccessResource) { From 3c09e96cf81d0fc4b2a927294b8b1ae528ae03b1 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 6 May 2022 16:19:16 +0800 Subject: [PATCH 165/338] [ISSUE #3949] Abstract PlainPermissionChecker --- .../acl/plain/PlainPermissionChecker.java | 61 +++++++++++++++++++ .../acl/plain/PlainPermissionManager.java | 35 +---------- 2 files changed, 62 insertions(+), 34 deletions(-) create mode 100644 acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java new file mode 100644 index 0000000000..0f15edecaa --- /dev/null +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.acl.plain; + +import java.util.Map; +import org.apache.rocketmq.acl.common.AclException; +import org.apache.rocketmq.acl.common.Permission; + +public class PlainPermissionChecker { + public static void check(PlainAccessResource needCheckedAccess, PlainAccessResource ownedAccess) { + if (Permission.needAdminPerm(needCheckedAccess.getRequestCode()) && !ownedAccess.isAdmin()) { + throw new AclException(String.format("Need admin permission for request code=%d, but accessKey=%s is not", needCheckedAccess.getRequestCode(), ownedAccess.getAccessKey())); + } + Map needCheckedPermMap = needCheckedAccess.getResourcePermMap(); + Map ownedPermMap = ownedAccess.getResourcePermMap(); + + if (needCheckedPermMap == null) { + // If the needCheckedPermMap is null,then return + return; + } + + if (ownedPermMap == null && ownedAccess.isAdmin()) { + // If the ownedPermMap is null and it is an admin user, then return + return; + } + + for (Map.Entry needCheckedEntry : needCheckedPermMap.entrySet()) { + String resource = needCheckedEntry.getKey(); + Byte neededPerm = needCheckedEntry.getValue(); + boolean isGroup = PlainAccessResource.isRetryTopic(resource); + + if (ownedPermMap == null || !ownedPermMap.containsKey(resource)) { + // Check the default perm + byte ownedPerm = isGroup ? ownedAccess.getDefaultGroupPerm() : + ownedAccess.getDefaultTopicPerm(); + if (!Permission.checkPermission(neededPerm, ownedPerm)) { + throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup))); + } + continue; + } + if (!Permission.checkPermission(neededPerm, ownedPermMap.get(resource))) { + throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup))); + } + } + } +} diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java index d29a9dd853..5b3848010f 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java @@ -559,40 +559,7 @@ public class PlainPermissionManager { } void checkPerm(PlainAccessResource needCheckedAccess, PlainAccessResource ownedAccess) { - if (Permission.needAdminPerm(needCheckedAccess.getRequestCode()) && !ownedAccess.isAdmin()) { - throw new AclException(String.format("Need admin permission for request code=%d, but accessKey=%s is not", needCheckedAccess.getRequestCode(), ownedAccess.getAccessKey())); - } - Map needCheckedPermMap = needCheckedAccess.getResourcePermMap(); - Map ownedPermMap = ownedAccess.getResourcePermMap(); - - if (needCheckedPermMap == null) { - // If the needCheckedPermMap is null,then return - return; - } - - if (ownedPermMap == null && ownedAccess.isAdmin()) { - // If the ownedPermMap is null and it is an admin user, then return - return; - } - - for (Map.Entry needCheckedEntry : needCheckedPermMap.entrySet()) { - String resource = needCheckedEntry.getKey(); - Byte neededPerm = needCheckedEntry.getValue(); - boolean isGroup = PlainAccessResource.isRetryTopic(resource); - - if (ownedPermMap == null || !ownedPermMap.containsKey(resource)) { - // Check the default perm - byte ownedPerm = isGroup ? ownedAccess.getDefaultGroupPerm() : - ownedAccess.getDefaultTopicPerm(); - if (!Permission.checkPermission(neededPerm, ownedPerm)) { - throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup))); - } - continue; - } - if (!Permission.checkPermission(neededPerm, ownedPermMap.get(resource))) { - throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup))); - } - } + PlainPermissionChecker.check(needCheckedAccess, ownedAccess); } void clearPermissionInfo() { From 4882427b4ce72b2c5b85ebc71251ef041af2f769 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Sat, 7 May 2022 10:38:46 +0800 Subject: [PATCH 166/338] [ISSUE #3949] for check style and test case --- .../broker/processor/PopMessageProcessorTest.java | 10 ---------- pom.xml | 1 + 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java index 67b4fb96cb..85582fcff9 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java @@ -110,16 +110,6 @@ public class PopMessageProcessorTest { assertThat(response.getRemark()).contains("topic[" + topic + "] not exist"); } - @Test - public void testProcessRequest_SubNotExist() throws RemotingCommandException { - brokerController.getConsumerManager().unregisterConsumer(group, clientChannelInfo, false); - final RemotingCommand request = createPopMsgCommand(); - RemotingCommand response = popMessageProcessor.processRequest(handlerContext, request); - assertThat(response).isNotNull(); - assertThat(response.getCode()).isEqualTo(ResponseCode.SUBSCRIPTION_NOT_EXIST); - assertThat(response.getRemark()).contains("consumer's group info not exist"); - } - @Test public void testProcessRequest_Found() throws RemotingCommandException { GetMessageResult getMessageResult = createGetMessageResult(1); diff --git a/pom.xml b/pom.xml index def3cb5cee..9caa47358d 100644 --- a/pom.xml +++ b/pom.xml @@ -244,6 +244,7 @@ */*.iml docs/** localbin/** + conf/rmq-proxy.json From 98ada9886411972d0959b20befd1901336f7469f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Sat, 7 May 2022 16:14:51 +0800 Subject: [PATCH 167/338] [ISSUE #3949] Rename grpc IT --- .../test/grpc/v2/{ClusterGrpcTest.java => ClusterGrpcIT.java} | 2 +- .../test/grpc/v2/{GrpcBaseTest.java => GrpcBaseIT.java} | 2 +- .../test/grpc/v2/{LocalGrpcTest.java => LocalGrpcIT.java} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename test/src/test/java/org/apache/rocketmq/test/grpc/v2/{ClusterGrpcTest.java => ClusterGrpcIT.java} (98%) rename test/src/test/java/org/apache/rocketmq/test/grpc/v2/{GrpcBaseTest.java => GrpcBaseIT.java} (99%) rename test/src/test/java/org/apache/rocketmq/test/grpc/v2/{LocalGrpcTest.java => LocalGrpcIT.java} (98%) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java similarity index 98% rename from test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index 82e6dc659c..3aa510ed0d 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -33,7 +33,7 @@ import org.junit.Test; import static org.awaitility.Awaitility.await; -public class ClusterGrpcTest extends GrpcBaseTest { +public class ClusterGrpcIT extends GrpcBaseIT { private GrpcForwardService grpcForwardService; diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java similarity index 99% rename from test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index a1a93620ba..c97fe4db1b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -106,7 +106,7 @@ import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HO import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -public class GrpcBaseTest extends BaseConf { +public class GrpcBaseIT extends BaseConf { protected final int PORT = 8082; /** diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java similarity index 98% rename from test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java rename to test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index d99b28ea99..df68948808 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcTest.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -26,7 +26,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -public class LocalGrpcTest extends GrpcBaseTest { +public class LocalGrpcIT extends GrpcBaseIT { private LocalGrpcService localGrpcService; @Before From 26b2098672be7d40878ba0c9093e77e5d812d6bd Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Sat, 7 May 2022 16:18:05 +0800 Subject: [PATCH 168/338] [ISSUE #3949] Adapt for authorization --- .../acl/common/AuthorizationHeader.java | 34 +++++-------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java index 5fd053a5f7..7e0406d8d0 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.acl.common; +import java.util.Arrays; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; @@ -25,14 +26,11 @@ public class AuthorizationHeader { private static final String HEADER_SEPARATOR = " "; private static final String CREDENTIALS_SEPARATOR = "/"; private static final int AUTH_HEADER_KV_LENGTH = 2; - private static final int CREDENTIALS_LENGTH = 3; private static final String CREDENTIAL = "Credential"; private static final String SIGNED_HEADERS = "SignedHeaders"; private static final String SIGNATURE = "Signature"; private String method; private String accessKey; - private String regionId; - private String channelKey; private String[] signedHeaders; private String signature; @@ -59,12 +57,10 @@ public class AuthorizationHeader { if (CREDENTIAL.equals(authItem)) { String[] credential = kv[1].split(CREDENTIALS_SEPARATOR); int credentialActualLength = credential.length; - if (credentialActualLength < CREDENTIALS_LENGTH) { + if (credentialActualLength == 0) { throw new DecoderException("authorization credential length is incorrect, actual length=" + credentialActualLength); } this.accessKey = credential[0]; - this.regionId = credential[1]; - this.channelKey = credential[2]; continue; } if (SIGNED_HEADERS.equals(authItem)) { @@ -90,14 +86,6 @@ public class AuthorizationHeader { return this.accessKey; } - public String getRegionId() { - return this.regionId; - } - - public String getChannelKey() { - return this.channelKey; - } - public String[] getSignedHeaders() { return this.signedHeaders; } @@ -114,14 +102,6 @@ public class AuthorizationHeader { this.accessKey = accessKey; } - public void setRegionId(final String regionId) { - this.regionId = regionId; - } - - public void setChannelKey(final String channelKey) { - this.channelKey = channelKey; - } - public void setSignedHeaders(final String[] signedHeaders) { this.signedHeaders = signedHeaders; } @@ -130,8 +110,12 @@ public class AuthorizationHeader { this.signature = signature; } - @java.lang.Override - public java.lang.String toString() { - return "GrpcAuthHeader(method=" + this.getMethod() + ", accessKey=" + this.getAccessKey() + ", regionId=" + this.getRegionId() + ", channelKey=" + this.getChannelKey() + ", signedHeaders=" + java.util.Arrays.deepToString(this.getSignedHeaders()) + ", signature=" + this.getSignature() + ")"; + @Override public String toString() { + return "AuthorizationHeader{" + + "method='" + method + '\'' + + ", accessKey='" + accessKey + '\'' + + ", signedHeaders=" + Arrays.toString(signedHeaders) + + ", signature='" + signature + '\'' + + '}'; } } From 56c393f00c528068ee4fc8d9c9e3a2d5fe69a304 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Sat, 7 May 2022 17:08:43 +0800 Subject: [PATCH 169/338] [ISSUE #3949] AddHeader in AuthenticationInterceptor --- .../interceptor/AuthenticationInterceptor.java | 14 +++++++++++++- .../grpc/interceptor/InterceptorConstants.java | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index b73c5cb085..bf40870adc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -25,8 +25,10 @@ import io.grpc.ServerCall; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; import java.util.List; +import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.plain.PlainAccessResource; import org.apache.rocketmq.proxy.grpc.v2.adapter.RequestMapping; public class AuthenticationInterceptor implements ServerInterceptor { @@ -56,10 +58,20 @@ public class AuthenticationInterceptor implements ServerInterceptor { .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) .build(); for (AccessValidator accessValidator : accessValidatorList) { - accessValidator.validate(accessValidator.parse(messageV3, metadataHeader)); + AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); + addHeader(headers, messageV3.getDescriptorForType().getFullName(), accessResource); + accessValidator.validate(accessResource); } super.onMessage(message); } }; } + + protected void addHeader(Metadata headers, String rpcName, AccessResource accessResource) { + headers.put(InterceptorConstants.RPC_NAME, rpcName); + if (accessResource instanceof PlainAccessResource) { + PlainAccessResource plainAccessResource = (PlainAccessResource) accessResource; + headers.put(InterceptorConstants.AUTHORIZATION_AK, plainAccessResource.getAccessKey()); + } + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index 0fe16789dd..62614b3a5e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -65,4 +65,7 @@ public class InterceptorConstants { public static final Metadata.Key CLIENT_ID = Metadata.Key.of("x-mq-client-id", Metadata.ASCII_STRING_MARSHALLER); + + public static final Metadata.Key AUTHORIZATION_AK + = Metadata.Key.of("x-mq-authorization-ak", Metadata.ASCII_STRING_MARSHALLER); } From 835714666e2c5a790769d8222dbf8cab2bc7b138 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Sat, 7 May 2022 17:34:29 +0800 Subject: [PATCH 170/338] [ISSUE #3949] Reserve time for longpolling --- .../java/org/apache/rocketmq/proxy/config/ProxyConfig.java | 2 +- .../rocketmq/proxy/grpc/v2/service/LocalGrpcService.java | 3 +-- .../test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) 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 d4625cf149..f3f2f6b2b6 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 @@ -73,7 +73,7 @@ public class ProxyConfig { private int transactionHeartbeatPeriodSecond = 20; private int transactionHeartbeatBatchNum = 100; - private long longPollingReserveTimeInMillis = 10000; + private long longPollingReserveTimeInMillis = 100; private boolean enableACL = false; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java index 414c480343..dbcf3bd638 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java @@ -51,7 +51,6 @@ import io.netty.channel.Channel; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerGroupEvent; @@ -265,7 +264,7 @@ public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcFo @Override public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - long pollTime = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); // TODO: get fifo config from subscriptionGroupManager boolean fifo = false; BaseReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index c97fe4db1b..64b4da7a7b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -139,6 +139,8 @@ public class GrpcBaseIT extends BaseConf { ConfigurationManager.intConfig(); ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); + // Set LongPollingReserveTimeInMillis to 500ms to reserve more time for IT + ConfigurationManager.getProxyConfig().setLongPollingReserveTimeInMillis(500); blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); From 7c77f4c324c01638f5ffb89c211d996a2464f3a6 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Sat, 7 May 2022 20:08:38 +0800 Subject: [PATCH 171/338] [ISSUE #3949] AddHeader in AuthenticationInterceptor --- .../proxy/grpc/interceptor/AuthenticationInterceptor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index bf40870adc..a3b75034b1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -59,16 +59,16 @@ public class AuthenticationInterceptor implements ServerInterceptor { .build(); for (AccessValidator accessValidator : accessValidatorList) { AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); - addHeader(headers, messageV3.getDescriptorForType().getFullName(), accessResource); accessValidator.validate(accessResource); + addHeader(headers, messageV3, accessResource); } super.onMessage(message); } }; } - protected void addHeader(Metadata headers, String rpcName, AccessResource accessResource) { - headers.put(InterceptorConstants.RPC_NAME, rpcName); + protected void addHeader(Metadata headers, GeneratedMessageV3 messageV3, AccessResource accessResource) { + headers.put(InterceptorConstants.RPC_NAME, messageV3.getDescriptorForType().getFullName()); if (accessResource instanceof PlainAccessResource) { PlainAccessResource plainAccessResource = (PlainAccessResource) accessResource; headers.put(InterceptorConstants.AUTHORIZATION_AK, plainAccessResource.getAccessKey()); From 74fedcbfadad43d5aa194a3b7cb577a19cdeeac4 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 10 May 2022 11:25:47 +0800 Subject: [PATCH 172/338] [ISSUE #3949] Add PermissionChecker --- .../rocketmq/acl/PermissionChecker.java | 22 +++++++++++++++++++ .../acl/plain/PlainPermissionChecker.java | 22 +++++++++++-------- .../acl/plain/PlainPermissionManager.java | 5 ++++- 3 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 acl/src/main/java/org/apache/rocketmq/acl/PermissionChecker.java diff --git a/acl/src/main/java/org/apache/rocketmq/acl/PermissionChecker.java b/acl/src/main/java/org/apache/rocketmq/acl/PermissionChecker.java new file mode 100644 index 0000000000..a38d3ec478 --- /dev/null +++ b/acl/src/main/java/org/apache/rocketmq/acl/PermissionChecker.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.acl; + +public interface PermissionChecker { + void check(AccessResource checkedAccess, AccessResource ownedAccess); +} diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java index 0f15edecaa..549c9fdce9 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionChecker.java @@ -18,23 +18,27 @@ package org.apache.rocketmq.acl.plain; import java.util.Map; +import org.apache.rocketmq.acl.AccessResource; +import org.apache.rocketmq.acl.PermissionChecker; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.Permission; -public class PlainPermissionChecker { - public static void check(PlainAccessResource needCheckedAccess, PlainAccessResource ownedAccess) { - if (Permission.needAdminPerm(needCheckedAccess.getRequestCode()) && !ownedAccess.isAdmin()) { - throw new AclException(String.format("Need admin permission for request code=%d, but accessKey=%s is not", needCheckedAccess.getRequestCode(), ownedAccess.getAccessKey())); +public class PlainPermissionChecker implements PermissionChecker { + public void check(AccessResource checkedAccess, AccessResource ownedAccess) { + PlainAccessResource checkedPlainAccess = (PlainAccessResource) checkedAccess; + PlainAccessResource ownedPlainAccess = (PlainAccessResource) ownedAccess; + if (Permission.needAdminPerm(checkedPlainAccess.getRequestCode()) && !ownedPlainAccess.isAdmin()) { + throw new AclException(String.format("Need admin permission for request code=%d, but accessKey=%s is not", checkedPlainAccess.getRequestCode(), ownedPlainAccess.getAccessKey())); } - Map needCheckedPermMap = needCheckedAccess.getResourcePermMap(); - Map ownedPermMap = ownedAccess.getResourcePermMap(); + Map needCheckedPermMap = checkedPlainAccess.getResourcePermMap(); + Map ownedPermMap = ownedPlainAccess.getResourcePermMap(); if (needCheckedPermMap == null) { // If the needCheckedPermMap is null,then return return; } - if (ownedPermMap == null && ownedAccess.isAdmin()) { + if (ownedPermMap == null && ownedPlainAccess.isAdmin()) { // If the ownedPermMap is null and it is an admin user, then return return; } @@ -46,8 +50,8 @@ public class PlainPermissionChecker { if (ownedPermMap == null || !ownedPermMap.containsKey(resource)) { // Check the default perm - byte ownedPerm = isGroup ? ownedAccess.getDefaultGroupPerm() : - ownedAccess.getDefaultTopicPerm(); + byte ownedPerm = isGroup ? ownedPlainAccess.getDefaultGroupPerm() : + ownedPlainAccess.getDefaultTopicPerm(); if (!Permission.checkPermission(neededPerm, ownedPerm)) { throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup))); } diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java index 5b3848010f..b315d367b2 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainPermissionManager.java @@ -37,6 +37,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.acl.PermissionChecker; import org.apache.rocketmq.acl.common.AclConstants; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.AclUtils; @@ -81,6 +82,8 @@ public class PlainPermissionManager { private List fileList = new ArrayList<>(); + private final PermissionChecker permissionChecker = new PlainPermissionChecker(); + public PlainPermissionManager() { load(); watch(); @@ -559,7 +562,7 @@ public class PlainPermissionManager { } void checkPerm(PlainAccessResource needCheckedAccess, PlainAccessResource ownedAccess) { - PlainPermissionChecker.check(needCheckedAccess, ownedAccess); + permissionChecker.check(needCheckedAccess, ownedAccess); } void clearPermissionInfo() { From d6720b5689b6bf15a6e131daddbd8d76be3ca092 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 10 May 2022 16:50:37 +0800 Subject: [PATCH 173/338] [ISSUE #3949] Interceptor * Add GlobalExceptionInterceptor * Catch AclException in AuthenticationInterceptor --- .../proxy/grpc/GrpcServerBuilder.java | 2 + .../AuthenticationInterceptor.java | 43 +++--- .../GlobalExceptionInterceptor.java | 128 ++++++++++++++++++ 3 files changed, 155 insertions(+), 18 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/GlobalExceptionInterceptor.java 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 02e6d3a9df..bd72629814 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 @@ -45,6 +45,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; +import org.apache.rocketmq.proxy.grpc.interceptor.GlobalExceptionInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; public class GrpcServerBuilder { @@ -150,6 +151,7 @@ public class GrpcServerBuilder { } this.serverBuilder + .intercept(new GlobalExceptionInterceptor()) .intercept(new ContextInterceptor()) .intercept(new HeaderInterceptor()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index a3b75034b1..d3c3063252 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -24,9 +24,12 @@ import io.grpc.Metadata; import io.grpc.ServerCall; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import java.util.List; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; +import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.MetadataHeader; import org.apache.rocketmq.acl.plain.PlainAccessResource; import org.apache.rocketmq.proxy.grpc.v2.adapter.RequestMapping; @@ -44,25 +47,29 @@ public class AuthenticationInterceptor implements ServerInterceptor { return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { @Override public void onMessage(R message) { - GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; - MetadataHeader metadataHeader = MetadataHeader.builder() - .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) - .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) - .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) - .datetime(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.DATE_TIME)) - .sessionToken(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.SESSION_TOKEN)) - .requestId(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REQUEST_ID)) - .language(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE)) - .clientVersion(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.CLIENT_VERSION)) - .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) - .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) - .build(); - for (AccessValidator accessValidator : accessValidatorList) { - AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); - accessValidator.validate(accessResource); - addHeader(headers, messageV3, accessResource); + try { + GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; + MetadataHeader metadataHeader = MetadataHeader.builder() + .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) + .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) + .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) + .datetime(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.DATE_TIME)) + .sessionToken(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.SESSION_TOKEN)) + .requestId(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REQUEST_ID)) + .language(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE)) + .clientVersion(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.CLIENT_VERSION)) + .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) + .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) + .build(); + for (AccessValidator accessValidator : accessValidatorList) { + AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); + accessValidator.validate(accessResource); + addHeader(headers, messageV3, accessResource); + } + super.onMessage(message); + } catch (AclException aclException) { + throw new StatusRuntimeException(Status.PERMISSION_DENIED, headers); } - super.onMessage(message); } }; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/GlobalExceptionInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/GlobalExceptionInterceptor.java new file mode 100644 index 0000000000..0c34b15743 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/GlobalExceptionInterceptor.java @@ -0,0 +1,128 @@ +/* + * 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.grpc.interceptor; + +import io.grpc.ForwardingServerCall; +import io.grpc.ForwardingServerCallListener; +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; + +public class GlobalExceptionInterceptor implements ServerInterceptor { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + @Override + public ServerCall.Listener interceptCall( + ServerCall call, + Metadata headers, + ServerCallHandler next + ) { + final ServerCall serverCall = new ClosableServerCall<>(call); + ServerCall.Listener delegate = next.startCall(serverCall, headers); + return new ForwardingServerCallListener.SimpleForwardingServerCallListener(delegate) { + @Override + public void onMessage(R message) { + try { + super.onMessage(message); + } catch (Throwable e) { + closeWithException(e); + } + } + + @Override + public void onHalfClose() { + try { + super.onHalfClose(); + } catch (Throwable e) { + closeWithException(e); + } + } + + @Override + public void onCancel() { + try { + super.onCancel(); + } catch (Throwable e) { + closeWithException(e); + } + } + + @Override + public void onComplete() { + try { + super.onComplete(); + } catch (Throwable e) { + closeWithException(e); + } + } + + @Override + public void onReady() { + try { + super.onReady(); + } catch (Throwable e) { + closeWithException(e); + } + } + + private void closeWithException(Throwable t) { + Metadata trailers = new Metadata(); + Status status = Status.INTERNAL.withDescription(t.getMessage()); + boolean printLog = true; + + if (t instanceof StatusRuntimeException) { + trailers = ((StatusRuntimeException) t).getTrailers(); + status = ((StatusRuntimeException) t).getStatus(); + // no error stack for permission denied. + if (status.getCode().value() == Status.PERMISSION_DENIED.getCode().value()) { + printLog = false; + } + } + + if (printLog) { + log.error("grpc server has exception. errorMsg:{}, e:", t.getMessage(), t); + } + + serverCall.close(status, trailers); + } + }; + } + + private static class ClosableServerCall extends + ForwardingServerCall.SimpleForwardingServerCall { + private boolean closeCalled = false; + + ClosableServerCall(ServerCall delegate) { + super(delegate); + } + + @Override + public synchronized void close(final Status status, final Metadata trailers) { + if (!closeCalled) { + closeCalled = true; + ClosableServerCall.super.close(status, trailers); + } + } + } +} From e549a67be359fec6ebf619dba23fcf1334d8bd65 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 16 May 2022 15:57:49 +0800 Subject: [PATCH 174/338] refactor: [ISSUE #3949] v2 support --- .../apache/rocketmq/common/BrokerConfig.java | 2 +- .../rocketmq/common/message/MessageBatch.java | 2 +- .../org/apache/rocketmq/proxy/ProxyMode.java | 57 ++ .../apache/rocketmq/proxy/ProxyStartup.java | 30 +- .../proxy/channel/ChannelManager.java | 135 ---- .../proxy/channel/InvocationChannel.java | 83 -- ...emetryCommandManager.java => Address.java} | 42 +- .../rocketmq/proxy/common/ProxyContext.java | 42 + ...CommandRecord.java => ProxyException.java} | 27 +- .../ProxyExceptionCode.java} | 8 +- .../proxy/common/utils/ExceptionUtils.java | 32 + .../rocketmq/proxy/config/ProxyConfig.java | 21 +- .../connector/AbstractForwardClient.java | 69 -- .../proxy/connector/ConnectorManager.java | 84 -- .../proxy/connector/DefaultForwardClient.java | 103 --- .../proxy/connector/ForwardProducer.java | 142 ---- .../proxy/connector/ForwardReadConsumer.java | 73 -- .../proxy/connector/ForwardWriteConsumer.java | 94 --- .../factory/AbstractClientManager.java | 86 -- .../factory/AbstractMQClientFactory.java | 66 -- .../factory/ForwardClientManager.java | 86 -- .../factory/TransactionProducerFactory.java | 38 - .../TransactionStateCheckRequest.java | 103 --- .../AuthenticationInterceptor.java | 1 - .../grpc/interceptor/RequestMapping.java | 57 ++ .../grpc/v2/AbstractMessingActivity.java | 42 + .../grpc/v2/DefaultGrpcMessingActivity.java | 154 ++++ ...elector.java => GrpcContextConstants.java} | 11 +- ...sor.java => GrpcMessagingApplication.java} | 53 +- ...dService.java => GrpcMessingActivity.java} | 4 +- .../proxy/grpc/v2/adapter/GrpcConverter.java | 733 ------------------ .../v2/adapter/channel/GrpcClientChannel.java | 169 ---- .../grpc/v2/channel/GrpcChannelManager.java | 84 ++ .../grpc/v2/channel/GrpcClientChannel.java | 200 +++++ .../proxy/grpc/v2/client/ClientActivity.java | 360 +++++++++ .../GrpcClientSettingsManager.java} | 11 +- .../proxy/grpc/v2/common/GrpcConverter.java | 229 ++++++ .../grpc/v2/common/GrpcProxyException.java | 62 ++ .../{adapter => common}/ResponseBuilder.java | 18 +- .../{adapter => common}/ResponseWriter.java | 2 +- .../grpc/v2/consumer/AckMessageActivity.java | 118 +++ .../ChangeInvisibleDurationActivity.java | 76 ++ .../consumer/PopMessageResultFilterImpl.java | 46 ++ .../v2/consumer/ReceiveMessageActivity.java | 129 +++ .../ReceiveMessageResponseStreamWriter.java | 137 ++++ .../producer/ForwardMessageToDLQActivity.java | 65 ++ .../grpc/v2/producer/SendMessageActivity.java | 244 ++++++ .../proxy/grpc/v2/route/RouteActivity.java | 246 ++++++ .../grpc/v2/service/AbstractRouteService.java | 99 --- ...aseReceiveMessageResponseStreamWriter.java | 122 --- .../BaseReceiveMessageResultFilter.java | 67 -- .../proxy/grpc/v2/service/BaseService.java | 77 -- .../v2/service/ClientSettingsService.java | 65 -- .../grpc/v2/service/ClusterGrpcService.java | 183 ----- .../grpc/v2/service/LocalGrpcService.java | 565 -------------- .../ReceiveMessageResponseStreamObserver.java | 67 -- .../v2/service/cluster/ConsumerService.java | 283 ------- .../DefaultAssignmentQueueSelector.java | 41 - .../cluster/DefaultReadQueueSelector.java | 55 -- ...ultReceiveMessageResponseStreamWriter.java | 96 --- .../DefaultReceiveMessageResultFilter.java | 127 --- .../cluster/DefaultWriteQueueSelector.java | 77 -- .../service/cluster/ForwardClientService.java | 266 ------- .../v2/service/cluster/ProducerService.java | 184 ----- .../grpc/v2/service/cluster/RouteService.java | 150 ---- .../service/cluster/TransactionService.java | 139 ---- ...calReceiveMessageResponseStreamWriter.java | 76 -- .../LocalReceiveMessageResultFilter.java | 94 --- .../local/LocalWriteQueueSelector.java | 101 --- .../grpc/v2/service/local/RouteService.java | 175 ----- .../transaction/EndTransactionActivity.java | 74 ++ .../proxy/processor/AbstractProcessor.java | 40 + .../proxy/processor/ClientProcessor.java | 104 +++ .../proxy/processor/ConsumerProcessor.java | 200 +++++ .../processor/DefaultMessagingProcessor.java | 168 ++++ .../proxy/processor/MessagingProcessor.java | 222 ++++++ .../PopMessageResultFilter.java} | 20 +- .../proxy/processor/ProducerProcessor.java | 136 ++++ .../QueueSelector.java} | 13 +- .../proxy/processor/TransactionProcessor.java | 80 ++ .../proxy/processor/TransactionStatus.java | 23 + .../proxy/service/ClusterServiceManager.java | 152 ++++ .../proxy/service/LocalServiceManager.java | 84 ++ .../proxy/service/ServiceManager.java | 58 ++ .../message/AbstractMessageService.java | 44 ++ .../message/ClusterMessageService.java | 133 ++++ .../service/message/LocalMessageService.java | 78 ++ .../message/LocalRemotingCommand.java} | 24 +- .../proxy/service/message/MessageService.java | 86 ++ .../DoNothingClientRemotingProcessor.java | 2 +- .../mqclient}/MQClientAPIExt.java | 19 +- .../service/mqclient/MQClientAPIFactory.java | 115 +++ .../ProxyClientRemotingProcessor.java | 36 +- .../service/out/ClusterProxyOutService.java | 42 + .../service/out/LocalProxyOutService.java | 63 ++ .../proxy/service/out/ProxyChannel.java | 171 ++++ .../proxy/service/out/ProxyOutService.java | 37 + .../route/ClusterTopicRouteService.java | 66 ++ .../service/route/LocalTopicRouteService.java | 102 +++ .../route/MessageQueueSelector.java | 2 +- .../route/MessageQueueView.java} | 10 +- .../service/route/ProxyTopicRouteData.java | 77 ++ .../route/SelectableMessageQueue.java | 2 +- .../route/TopicRouteHelper.java | 2 +- .../route/TopicRouteService.java} | 111 ++- .../route/TopicRouteWrapper.java | 2 +- .../ClusterTransactionService.java} | 60 +- .../transaction/LocalTransactionService.java | 37 + .../transaction/TransactionId.java | 94 ++- .../transaction/TransactionService.java} | 17 +- .../config/ConfigurationManagerTest.java | 2 +- .../cluster/ForwardClientServiceTest.java | 142 ---- .../cluster/TransactionServiceTest.java | 105 --- ...eceiveMessageResponseStreamWriterTest.java | 170 ---- .../LocalReceiveMessageResultFilterTest.java | 135 ---- .../proxy/processor/BaseProcessorTest.java | 103 +++ .../processor/ConsumerProcessorTest.java | 174 +++++ .../processor/ProducerProcessorTest.java | 24 + .../transaction/TransactionIdTest.java | 17 +- .../backup/channel/InvocationChannel.java | 83 ++ .../backup}/channel/InvocationContext.java | 0 .../backup}/channel/SimpleChannel.java | 2 +- .../channel/SimpleChannelHandlerContext.java | 2 +- .../backup/grpc/v2/adapter/GrpcConverter.java | 733 ++++++++++++++++++ .../grpc/v2/adapter/ProxyException.java | 0 .../backup}/grpc/v2/adapter/ProxyMode.java | 0 .../grpc/v2/adapter/RequestMapping.java | 0 .../backup}/grpc/v2/adapter/ResponseHook.java | 4 +- .../channel/ReceiveMessageChannel.java | 0 .../adapter/channel/SendMessageChannel.java | 0 .../ReceiveMessageResponseHandler.java | 0 .../v2/adapter/handler/ResponseHandler.java | 0 .../handler/SendMessageResponseHandler.java | 2 +- .../grpc/v2/service/AbstractRouteService.java | 99 +++ ...aseReceiveMessageResponseStreamWriter.java | 122 +++ .../BaseReceiveMessageResultFilter.java | 67 ++ .../backup/grpc/v2/service/BaseService.java | 77 ++ .../v2/service/ClientSettingsService.java | 65 ++ .../grpc/v2/service/ClusterGrpcActivity.java | 184 +++++ .../grpc/v2/service/LocalGrpcActivity.java | 566 ++++++++++++++ .../ReceiveMessageResponseStreamObserver.java | 67 ++ .../service/ReceiveMessageResultFilter.java | 29 + .../cluster/AssignmentQueueSelector.java | 27 + .../v2/service/cluster/ConsumerService.java | 283 +++++++ .../DefaultAssignmentQueueSelector.java | 41 + .../cluster/DefaultReadQueueSelector.java | 55 ++ ...ultReceiveMessageResponseStreamWriter.java | 96 +++ .../DefaultReceiveMessageResultFilter.java | 127 +++ .../cluster/DefaultWriteQueueSelector.java | 77 ++ .../service/cluster/ForwardClientService.java | 266 +++++++ .../v2/service/cluster/ProducerService.java | 184 +++++ .../v2/service/cluster/ReadQueueSelector.java | 27 + .../grpc/v2/service/cluster/RouteService.java | 150 ++++ .../service/cluster/TransactionService.java | 139 ++++ .../service/cluster/WriteQueueSelector.java | 26 + ...calReceiveMessageResponseStreamWriter.java | 76 ++ .../LocalReceiveMessageResultFilter.java | 94 +++ .../local/LocalWriteQueueSelector.java | 101 +++ .../grpc/v2/service/local/RouteService.java | 175 +++++ .../grpc/v2/service/LocalGrpcServiceTest.java | 8 +- .../v2/service/cluster/BaseServiceTest.java | 32 +- .../service/cluster/ConsumerServiceTest.java | 16 +- .../cluster/DefaultReadQueueSelectorTest.java | 8 +- .../DefaultWriteQueueSelectorTest.java | 10 +- .../cluster/ForwardClientServiceTest.java | 142 ++++ .../service/cluster/ProducerServiceTest.java | 4 +- .../v2/service/cluster/RouteServiceTest.java | 10 +- .../cluster/TransactionServiceTest.java | 104 +++ .../LocalPopMessageResultFilterTest.java | 135 ++++ ...eceiveMessageResponseStreamWriterTest.java | 170 ++++ .../local/LocalWriteQueueSelectorTest.java | 2 +- .../v2/service/local/RouteServiceTest.java | 12 +- .../service}/ForwardClientManagerTest.java | 24 +- .../remoting/protocol/RemotingCommand.java | 2 +- .../rocketmq/test/grpc/v2/ClusterGrpcIT.java | 20 +- .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 20 +- 176 files changed, 10114 insertions(+), 6114 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/ProxyMode.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java rename proxy/src/main/java/org/apache/rocketmq/proxy/common/{TelemetryCommandManager.java => Address.java} (52%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java rename proxy/src/main/java/org/apache/rocketmq/proxy/common/{TelemetryCommandRecord.java => ProxyException.java} (66%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/transaction/TransactionStateChecker.java => common/ProxyExceptionCode.java} (82%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/RequestMapping.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{service/cluster/WriteQueueSelector.java => GrpcContextConstants.java} (71%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{GrpcMessagingProcessor.java => GrpcMessagingApplication.java} (78%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{service/GrpcForwardService.java => GrpcMessingActivity.java} (96%) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{service/GrpcClientManager.java => common/GrpcClientSettingsManager.java} (89%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{adapter => common}/ResponseBuilder.java (88%) rename proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/{adapter => common}/ResponseWriter.java (98%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/v2/service/cluster/ReadQueueSelector.java => processor/PopMessageResultFilter.java} (62%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/v2/service/cluster/AssignmentQueueSelector.java => processor/QueueSelector.java} (67%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionStatus.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/factory/MQClientFactory.java => service/message/LocalRemotingCommand.java} (51%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/processor => service/mqclient}/DoNothingClientRemotingProcessor.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/client => service/mqclient}/MQClientAPIExt.java (95%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/processor => service/mqclient}/ProxyClientRemotingProcessor.java (59%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector => service}/route/MessageQueueSelector.java (99%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/route/MessageQueueWrapper.java => service/route/MessageQueueView.java} (85%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector => service}/route/SelectableMessageQueue.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector => service}/route/TopicRouteHelper.java (97%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/route/TopicRouteCache.java => service/route/TopicRouteService.java} (55%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector => service}/route/TopicRouteWrapper.java (98%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector/transaction/TransactionHeartbeatRegisterService.java => service/transaction/ClusterTransactionService.java} (80%) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{connector => service}/transaction/TransactionId.java (79%) rename proxy/src/main/java/org/apache/rocketmq/proxy/{grpc/v2/service/ReceiveMessageResultFilter.java => service/transaction/TransactionService.java} (69%) delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java rename proxy/src/test/java/org/apache/rocketmq/proxy/{connector => service}/transaction/TransactionIdTest.java (81%) create mode 100644 proxy/src/test/resources/backup/channel/InvocationChannel.java rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/channel/InvocationContext.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/channel/SimpleChannel.java (99%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/channel/SimpleChannelHandlerContext.java (99%) create mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/ProxyException.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/ProxyMode.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/RequestMapping.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/ResponseHook.java (87%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/channel/ReceiveMessageChannel.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/channel/SendMessageChannel.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/handler/ResponseHandler.java (100%) rename proxy/src/{main/java/org/apache/rocketmq/proxy => test/resources/backup}/grpc/v2/adapter/handler/SendMessageResponseHandler.java (98%) create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java create mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/LocalGrpcServiceTest.java (98%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/BaseServiceTest.java (79%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java (95%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java (91%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java (92%) create mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/ProducerServiceTest.java (97%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/cluster/RouteServiceTest.java (96%) create mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java create mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java create mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java (98%) rename proxy/src/test/{java/org/apache/rocketmq => resources/backup/test}/proxy/grpc/v2/service/local/RouteServiceTest.java (89%) rename proxy/src/test/{java/org/apache/rocketmq/proxy/connector => resources/backup/test/proxy/service}/ForwardClientManagerTest.java (66%) 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 edb30b576d..df22fb1f8e 100644 --- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java @@ -248,7 +248,7 @@ public class BrokerConfig extends BrokerIdentity { * Transaction message check interval. */ @ImportantField - private long transactionCheckInterval = 60 * 1000; + private long transactionCheckInterval = 3 * 1000; /** * Acl feature switch diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageBatch.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageBatch.java index a6b801edab..e3104f1656 100644 --- a/common/src/main/java/org/apache/rocketmq/common/message/MessageBatch.java +++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageBatch.java @@ -39,7 +39,7 @@ public class MessageBatch extends Message implements Iterable { return messages.iterator(); } - public static MessageBatch generateFromList(Collection messages) { + public static MessageBatch generateFromList(Collection messages) { assert messages != null; assert messages.size() > 0; List messageList = new ArrayList(messages.size()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyMode.java new file mode 100644 index 0000000000..3cc36425b0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyMode.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy; + +public enum ProxyMode { + LOCAL("LOCAL"), + CLUSTER("CLUSTER"); + + private final String mode; + + ProxyMode(String mode) { + this.mode = mode; + } + + public static boolean isClusterMode(String mode) { + if (mode == null) { + return false; + } + return CLUSTER.mode.equals(mode.toUpperCase()); + } + + public static boolean isClusterMode(ProxyMode mode) { + if (mode == null) { + return false; + } + return CLUSTER.equals(mode); + } + + public static boolean isLocalMode(String mode) { + if (mode == null) { + return false; + } + return LOCAL.mode.equals(mode.toUpperCase()); + } + + public static boolean isLocalMode(ProxyMode mode) { + if (mode == null) { + return false; + } + return LOCAL.equals(mode); + } +} 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 1ba8feb444..fe09ef38cc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -36,11 +36,9 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; import org.apache.rocketmq.proxy.grpc.GrpcServerBuilder; -import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; -import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; -import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.remoting.RPCHook; import org.slf4j.LoggerFactory; public class ProxyStartup { @@ -65,9 +63,11 @@ public class ProxyStartup { ThreadPoolExecutor executor = createServerExecutor(); + ServiceManager serviceManager = createServiceManager(null); + // create grpcServer GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor) - .addService(createServiceProcessor()) + .addService(createServiceProcessor(serviceManager)) .configInterceptor() .build(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); @@ -94,11 +94,12 @@ public class ProxyStartup { log.info(new Date() + " rmq-proxy startup successfully"); } - private static GrpcMessagingProcessor createServiceProcessor() { - GrpcForwardService grpcService; + private static ServiceManager createServiceManager(RPCHook rpcHook) { String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); + ServiceManager serviceManager; + if (ProxyMode.isClusterMode(proxyModeStr)) { - grpcService = new ClusterGrpcService(); + serviceManager = ServiceManager.createForClusterMode(rpcHook); } else if (ProxyMode.isLocalMode(proxyModeStr)) { BrokerController brokerController = createBrokerController(); StartAndShutdown brokerControllerWrapper = new StartAndShutdown() { @@ -113,13 +114,18 @@ public class ProxyStartup { } }; PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(brokerControllerWrapper); - grpcService = new LocalGrpcService(brokerController); + serviceManager = ServiceManager.createForLocalMode(brokerController, rpcHook); } else { throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); } + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(serviceManager); + return serviceManager; + } - PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcService); - return new GrpcMessagingProcessor(grpcService); + private static GrpcMessagingApplication createServiceProcessor(ServiceManager serviceManager) { + GrpcMessagingApplication application = GrpcMessagingApplication.create(serviceManager); + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(application); + return application; } private static BrokerController createBrokerController() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java deleted file mode 100644 index e09180c5b7..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/ChannelManager.java +++ /dev/null @@ -1,135 +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.proxy.channel; - -import io.grpc.Context; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; - -public class ChannelManager { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - protected final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); - protected final ConcurrentMap/* clientId */> groupClientIdMap = new ConcurrentHashMap<>(); - - public SimpleChannel createChannel(Context ctx) { - return createChannel(ctx, anonymousChannelId(ctx)); - } - - public SimpleChannel createChannel(Context ctx, String clientId) { - return createChannel(ctx, clientId, ChannelManager::createSimpleChannelDirectly, SimpleChannel.class); - } - - public T createChannel(Context ctx, Function creator, Class clazz) { - return createChannel(ctx, anonymousChannelId(ctx, clazz.getName()), creator, clazz); - } - - public T createChannel(Context ctx, String clientId, Function creator, Class clazz) { - if (StringUtils.isBlank(clientId)) { - log.warn("ClientId is unexpected null or empty"); - return creator.apply(ctx); - } - - clientIdChannelMap.computeIfAbsent(clientId, key -> creator.apply(ctx)); - - T channel = clazz.cast(clientIdChannelMap.get(clientId)); - channel.updateLastAccessTime(); - return channel; - } - - public T getChannel(String clientId, Class clazz) { - SimpleChannel channel = clientIdChannelMap.get(clientId); - if (channel == null) { - return null; - } - return clazz.cast(channel); - } - - public void setChannel(String clientId, T channel) { - clientIdChannelMap.put(clientId, channel); - } - - public T removeChannel(String clientId, Class clazz) { - SimpleChannel channel = clientIdChannelMap.remove(clientId); - if (channel == null) { - return null; - } - return clazz.cast(channel); - } - - private String anonymousChannelId(Context ctx) { - final String clientHost = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.LOCAL_ADDRESS); - return clientHost + "@" + localAddress; - } - - private String anonymousChannelId(Context ctx, String className) { - final String clientHost = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.LOCAL_ADDRESS); - return className + "@" + clientHost + "@" + localAddress; - } - - public static SimpleChannel createSimpleChannelDirectly(Context ctx) { - final String clientHost = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.REMOTE_ADDRESS); - final String localAddress = InterceptorConstants.METADATA.get(ctx) - .get(InterceptorConstants.LOCAL_ADDRESS); - return new SimpleChannel(null, clientHost, localAddress, ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds()); - } - - public void addGroupClientId(String group, String clientId) { - groupClientIdMap.computeIfAbsent(group, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())) - .add(clientId); - } - - public List getClientIdList(String group) { - return new ArrayList<>(groupClientIdMap.get(group)); - } - - public void onClientOffline(String clientId) { - SimpleChannel simpleChannel = clientIdChannelMap.remove(clientId); - if (simpleChannel == null) { - return; - } - if (simpleChannel instanceof GrpcClientChannel) { - GrpcClientChannel grpcClientChannel = (GrpcClientChannel) simpleChannel; - groupClientIdMap.computeIfPresent(grpcClientChannel.getGroup(), (group, clientIds) -> { - clientIds.remove(grpcClientChannel.getClientId()); - if (clientIds.isEmpty()) { - return null; - } - return clientIds; - }); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java deleted file mode 100644 index 2ae543f254..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationChannel.java +++ /dev/null @@ -1,83 +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.proxy.channel; - -import io.grpc.Context; -import io.netty.channel.ChannelFuture; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import org.apache.rocketmq.proxy.common.Cleaner; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ResponseHandler; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public abstract class InvocationChannel extends SimpleChannel implements Cleaner { - protected final ConcurrentMap> inFlightRequestMap; - protected final ResponseHandler handler; - - public InvocationChannel(Context ctx, ResponseHandler handler) { - super(ChannelManager.createSimpleChannelDirectly(ctx)); - this.inFlightRequestMap = new ConcurrentHashMap<>(); - this.handler = handler; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - if (msg instanceof RemotingCommand) { - RemotingCommand responseCommand = (RemotingCommand) msg; - InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); - if (null != context) { - handler.handle(responseCommand, context); - } - inFlightRequestMap.remove(responseCommand.getOpaque()); - } - return super.writeAndFlush(msg); - } - - @Override - public boolean isWritable() { - return inFlightRequestMap.size() > 0; - } - - public void registerInvocationContext(int opaque, InvocationContext context) { - inFlightRequestMap.put(opaque, context); - } - - public void eraseInvocationContext(int opaque) { - inFlightRequestMap.remove(opaque); - } - - @Override - public void clean() { - Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); - int count = 0; - while (iterator.hasNext()) { - Map.Entry> entry = iterator.next(); - if (entry.getValue().expired(expiredTimeSec)) { - iterator.remove(); - count++; - log.debug("An expired request is found, created time-point: {}, Request: {}", - entry.getValue().getTimestamp(), entry.getValue().getRequest()); - } - } - if (count > 0) { - log.warn("[BUG] {} expired in-flight requests is cleaned.", count); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java similarity index 52% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java index 99461ed39b..7480fb2fa0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java @@ -14,24 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.rocketmq.proxy.common; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; +import com.google.common.net.HostAndPort; -public class TelemetryCommandManager { - protected final ConcurrentMap commandTable = new ConcurrentHashMap<>(); - protected final AtomicLong commandIdGenerator = new AtomicLong(0); +public class Address { - public String putCommand(int opaque) { - String nonce = String.valueOf(commandIdGenerator.incrementAndGet()); - commandTable.put(nonce, new TelemetryCommandRecord(nonce, opaque)); - return nonce; + public enum AddressScheme { + IPv4, + IPv6, + DOMAIN_NAME, + UNRECOGNIZED } - public TelemetryCommandRecord getCommand(String commandId) { - return commandTable.get(commandId); + private AddressScheme addressScheme; + private HostAndPort hostAndPort; + + public Address(AddressScheme addressScheme, HostAndPort hostAndPort) { + this.addressScheme = addressScheme; + this.hostAndPort = hostAndPort; + } + + public AddressScheme getAddressScheme() { + return addressScheme; + } + + public void setAddressScheme(AddressScheme addressScheme) { + this.addressScheme = addressScheme; + } + + public HostAndPort getHostAndPort() { + return hostAndPort; + } + + public void setHostAndPort(HostAndPort hostAndPort) { + this.hostAndPort = hostAndPort; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java new file mode 100644 index 0000000000..be0f6d4b00 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.common; + +import java.util.HashMap; +import java.util.Map; + +public class ProxyContext { + private final Map value = new HashMap<>(); + + public static ProxyContext create() { + return new ProxyContext(); + } + + public Map getValue() { + return this.value; + } + + public ProxyContext withVal(String key, Object val) { + this.value.put(key, val); + return this; + } + + public T getVal(String key) { + return (T) this.value.get(key); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyException.java similarity index 66% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyException.java index adc074113f..af528329fd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/TelemetryCommandRecord.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyException.java @@ -14,28 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.rocketmq.proxy.common; -public class TelemetryCommandRecord { - private final String nonce; - private final Integer opaque; +public class ProxyException extends RuntimeException { - public TelemetryCommandRecord(String nonce, int opaque) { - this.nonce = nonce; - this.opaque = opaque; + private final ProxyExceptionCode code; + + public ProxyException(ProxyExceptionCode code, String message) { + super(message); + this.code = code; } - public TelemetryCommandRecord(String nonce) { - this.nonce = nonce; - this.opaque = null; + public ProxyException(ProxyExceptionCode code, String message, Throwable cause) { + super(message, cause); + this.code = code; } - public String getNonce() { - return nonce; - } - - public Integer getOpaque() { - return opaque; + public ProxyExceptionCode getCode() { + return code; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java similarity index 82% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 506aa0154c..95b3a93f69 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateChecker.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -14,8 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.transaction; +package org.apache.rocketmq.proxy.common; -public interface TransactionStateChecker { - void checkTransactionState(TransactionStateCheckRequest checkData); +public enum ProxyExceptionCode { + FORBIDDEN, + RECEIPT_HANDLE_EXPIRED, + INVALID_BROKER_NAME } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java new file mode 100644 index 0000000000..78b32e4cb0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.common.utils; + +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; + +public class ExceptionUtils { + + public static Throwable getRealException(Throwable throwable) { + if (throwable instanceof CompletionException || throwable instanceof ExecutionException) { + if (throwable.getCause() != null) { + throwable = throwable.getCause(); + } + } + return throwable; + } +} 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 f3f2f6b2b6..43a11bab4d 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 @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; @@ -54,6 +54,9 @@ public class ProxyConfig { private int channelExpiredInSeconds = 60; + private int rocketmqMQClientNum = 6; + private double rocketmqMQClientWorkerFactor = 0.2f; + private int forwardConsumerNum = 2; private double forwardConsumerWorkerFactor = 0.2f; private int forwardProducerNum = 2; @@ -229,6 +232,22 @@ public class ProxyConfig { this.channelExpiredInSeconds = channelExpiredInSeconds; } + public int getRocketmqMQClientNum() { + return rocketmqMQClientNum; + } + + public void setRocketmqMQClientNum(int rocketmqMQClientNum) { + this.rocketmqMQClientNum = rocketmqMQClientNum; + } + + public double getRocketmqMQClientWorkerFactor() { + return rocketmqMQClientWorkerFactor; + } + + public void setRocketmqMQClientWorkerFactor(double rocketmqMQClientWorkerFactor) { + this.rocketmqMQClientWorkerFactor = rocketmqMQClientWorkerFactor; + } + public int getForwardConsumerNum() { return forwardConsumerNum; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java deleted file mode 100644 index 2dce57491e..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/AbstractForwardClient.java +++ /dev/null @@ -1,69 +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.proxy.connector; - -import java.time.Duration; -import java.util.concurrent.ThreadLocalRandom; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; - -public abstract class AbstractForwardClient implements StartAndShutdown { - public static final long MAX_CONSUMER_TIMEOUT_MILLIS = Duration.ofSeconds(20).toMillis(); - public static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis(); - - private final ForwardClientManager clientFactory; - private MQClientAPIExt[] clients; - private final String gidPrefix; - - public AbstractForwardClient(ForwardClientManager clientFactory, String gidPrefix) { - this.clientFactory = clientFactory; - this.gidPrefix = gidPrefix; - } - - protected abstract int getClientNum(); - - protected abstract MQClientAPIExt createNewClient(ForwardClientManager forwardClientFactory, String name); - - protected String getNamePrefix() { - return this.gidPrefix; - } - - protected MQClientAPIExt getClient() { - if (clients.length == 1) { - return this.clients[0]; - } - int index = ThreadLocalRandom.current().nextInt(this.clients.length); - return this.clients[index]; - } - - @Override - public void start() throws Exception { - int clientCount = getClientNum(); - this.clients = new MQClientAPIExt[clientCount]; - - for (int i = 0; i < clientCount; i++) { - String name = getNamePrefix() + "N_" + i; - clients[i] = createNewClient(clientFactory, name); - } - } - - @Override - public void shutdown() throws Exception { - - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java deleted file mode 100644 index e0495c319e..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ConnectorManager.java +++ /dev/null @@ -1,84 +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.proxy.connector; - -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; - -public class ConnectorManager extends AbstractStartAndShutdown { - protected ForwardClientManager forwardClientManager; - protected DefaultForwardClient defaultForwardClient; - protected ForwardProducer forwardProducer; - protected ForwardReadConsumer forwardReadConsumer; - protected ForwardWriteConsumer forwardWriteConsumer; - - protected TopicRouteCache topicRouteCache; - protected TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; - - public ConnectorManager(TransactionStateChecker transactionStateChecker) { - this.init(transactionStateChecker); - } - - protected void init(TransactionStateChecker transactionStateChecker) { - this.forwardClientManager = new ForwardClientManager(transactionStateChecker); - this.defaultForwardClient = new DefaultForwardClient(this.forwardClientManager); - this.forwardProducer = new ForwardProducer(this.forwardClientManager); - this.forwardReadConsumer = new ForwardReadConsumer(this.forwardClientManager); - this.forwardWriteConsumer = new ForwardWriteConsumer(this.forwardClientManager); - - this.topicRouteCache = new TopicRouteCache(this.defaultForwardClient); - this.transactionHeartbeatRegisterService = new TransactionHeartbeatRegisterService(this.forwardProducer, this.topicRouteCache); - - this.appendStartAndShutdown(this.forwardClientManager); - this.appendStartAndShutdown(this.defaultForwardClient); - this.appendStartAndShutdown(this.forwardProducer); - this.appendStartAndShutdown(this.forwardReadConsumer); - this.appendStartAndShutdown(this.forwardWriteConsumer); - this.appendStartAndShutdown(this.transactionHeartbeatRegisterService); - } - - public ForwardClientManager getForwardClientManager() { - return forwardClientManager; - } - - public DefaultForwardClient getDefaultForwardClient() { - return defaultForwardClient; - } - - public ForwardProducer getForwardProducer() { - return forwardProducer; - } - - public ForwardReadConsumer getForwardReadConsumer() { - return forwardReadConsumer; - } - - public ForwardWriteConsumer getForwardWriteConsumer() { - return forwardWriteConsumer; - } - - public TopicRouteCache getTopicRouteCache() { - return topicRouteCache; - } - - public TransactionHeartbeatRegisterService getTransactionHeartbeatRegisterService() { - return transactionHeartbeatRegisterService; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java deleted file mode 100644 index ee7b1e45c7..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/DefaultForwardClient.java +++ /dev/null @@ -1,103 +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.proxy.connector; - -import io.grpc.Context; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; -import org.apache.rocketmq.remoting.exception.RemotingException; - -public class DefaultForwardClient extends AbstractForwardClient { - private static final String CID_PREFIX = "CID_RMQ_PROXY_DEFAULT_"; - - public DefaultForwardClient(ForwardClientManager clientFactory) { - super(clientFactory, CID_PREFIX); - } - - @Override - protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getDefaultForwardClientNum(); - } - - @Override - protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getDefaultForwardClientWorkerFactor(); - int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); - - return clientFactory.getMQClient(name, threadCount); - } - - public CompletableFuture> getConsumerListByGroup( - Context ctx, - String brokerAddr, - GetConsumerListByGroupRequestHeader requestHeader, - long timeoutMillis - ) { - return this.getClient().getConsumerListByGroupAsync(brokerAddr, requestHeader, timeoutMillis); - } - - public TopicRouteData getTopicRouteInfoFromNameServer(String topic) - throws RemotingException, InterruptedException, MQClientException { - return this.getTopicRouteInfoFromNameServer(topic, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public TopicRouteData getTopicRouteInfoFromNameServer(String topic, long timeoutMillis) - throws RemotingException, InterruptedException, MQClientException { - return this.getClient().getTopicRouteInfoFromNameServer(topic, timeoutMillis); - } - - public CompletableFuture getMaxOffset(Context ctx, String brokerAddr, String topic, int queueId) { - return this.getMaxOffset(ctx, brokerAddr, topic, queueId, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture getMaxOffset( - Context ctx, - String brokerAddr, - String topic, - int queueId, - long timeoutMillis - ) { - return this.getClient().getMaxOffsetAsync(brokerAddr, topic, queueId, timeoutMillis); - } - - public CompletableFuture searchOffset( - Context ctx, - String brokerAddr, - String topic, - int queueId, - long timestamp - ) { - return this.searchOffset(ctx, brokerAddr, topic, queueId, timestamp, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture searchOffset( - Context ctx, - String brokerAddr, - String topic, - int queueId, - long timestamp, - long timeoutMillis - ) { - return this.getClient().searchOffsetAsync(brokerAddr, topic, queueId, timestamp, timeoutMillis); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java deleted file mode 100644 index 12a7a8c1d2..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardProducer.java +++ /dev/null @@ -1,142 +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.proxy.connector; - -import io.grpc.Context; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class ForwardProducer extends AbstractForwardClient { - private static final String PID_PREFIX = "PID_RMQ_PROXY_PUBLISH_MESSAGE_"; - - public ForwardProducer(ForwardClientManager clientFactory) { - super(clientFactory, PID_PREFIX); - } - - @Override - protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getForwardProducerNum(); - } - - @Override - protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getForwardProducerWorkerFactor(); - final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); - - return clientFactory.getTransactionalProducer(name, threadCount); - } - - public CompletableFuture heartBeat(Context ctx, String brokerAddr, HeartbeatData heartbeatData) throws Exception { - return this.heartBeat(ctx, brokerAddr, heartbeatData, DEFAULT_MQ_CLIENT_TIMEOUT); - } - public CompletableFuture heartBeat(Context ctx, String brokerAddr, HeartbeatData heartbeatData, long timeout) throws Exception { - return this.getClient().sendHeartbeatAsync(brokerAddr, heartbeatData, timeout); - } - - public void endTransaction(Context ctx, String brokerAddr, EndTransactionRequestHeader requestHeader) throws Exception { - this.endTransaction(ctx, brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public void endTransaction(Context ctx, String brokerAddr, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws Exception { - this.getClient().endTransactionOneway(brokerAddr, requestHeader, "end transaction from rmq proxy", timeoutMillis); - } - - public CompletableFuture sendMessage( - Context ctx, - String address, - String brokerName, - List msg, - SendMessageRequestHeader requestHeader - ) { - return this.sendMessage(ctx, address, brokerName, msg, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture sendMessage( - Context ctx, - String address, - String brokerName, - List msg, - SendMessageRequestHeader requestHeader, - long timeoutMillis - ) { - CompletableFuture future; - if (msg.size() == 1) { - future = this.getClient().sendMessageAsync(address, brokerName, msg.get(0), requestHeader, timeoutMillis); - } else { - future = this.getClient().sendMessageAsync(address, brokerName, msg, requestHeader, timeoutMillis); - } - return processSendMessageResponseFuture(ctx, address, requestHeader, future); - } - - protected CompletableFuture processSendMessageResponseFuture( - Context ctx, - String address, - SendMessageRequestHeader requestHeader, - CompletableFuture future) { - return future.thenApply(sendResult -> { - int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { - TransactionId transactionId = TransactionId.genByBrokerTransactionId(address, sendResult); - sendResult.setTransactionId(transactionId.getProxyTransactionId()); - } - return sendResult; - }); - } - - public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, - AckMessageRequestHeader ackMessageRequestHeader) { - return sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader, DEFAULT_MQ_CLIENT_TIMEOUT, - future -> { - }); - } - - public CompletableFuture sendMessageBackThenAckOrg(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader, - AckMessageRequestHeader ackMessageRequestHeader, long timeoutMillis, - Consumer> ackFutureSetter) { - return this.sendMessageBack(ctx, brokerAddr, sendMsgBackRequestHeader, timeoutMillis).whenComplete((result, throwable) -> { - if (throwable != null || ResponseCode.SUCCESS != result.getCode()) { - return; - } - ackFutureSetter.accept(this.getClient().ackMessageAsync(brokerAddr, ackMessageRequestHeader, timeoutMillis)); - }); - } - - public CompletableFuture sendMessageBack(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader) { - return this.sendMessageBack(ctx, brokerAddr, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture sendMessageBack(Context ctx, String brokerAddr, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { - return this.getClient().sendMessageBackAsync(brokerAddr, requestHeader, timeoutMillis); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java deleted file mode 100644 index 13973e8882..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardReadConsumer.java +++ /dev/null @@ -1,73 +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.proxy.connector; - -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.consumer.PopResult; -import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; - -public class ForwardReadConsumer extends AbstractForwardClient { - - private static final String CID_PREFIX = "CID_RMQ_PROXY_CONSUME_MESSAGE_"; - - public ForwardReadConsumer(ForwardClientManager clientFactory) { - super(clientFactory, CID_PREFIX); - } - - @Override - protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getForwardConsumerNum(); - } - - @Override - protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); - final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); - - return clientFactory.getMQClient(name, threadCount); - } - - public CompletableFuture popMessage(Context ctx, String address, String brokerName, - PopMessageRequestHeader requestHeader) { - return this.popMessage(ctx, address, brokerName, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture popMessage( - Context ctx, - String address, - String brokerName, - PopMessageRequestHeader requestHeader, - long timeoutMillis - ) { - return this.getClient().popMessageAsync(address, brokerName, requestHeader, timeoutMillis); - } - - public CompletableFuture pullMessage(Context ctx, String address, PullMessageRequestHeader requestHeader) { - return this.pullMessage(ctx, address, requestHeader, MAX_CONSUMER_TIMEOUT_MILLIS); - } - - public CompletableFuture pullMessage(Context ctx, String address, PullMessageRequestHeader requestHeader, - long timeoutMillis) { - return this.getClient().pullMessageAsync(address, requestHeader, timeoutMillis); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java deleted file mode 100644 index 5404c77a96..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/ForwardWriteConsumer.java +++ /dev/null @@ -1,94 +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.proxy.connector; - -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.factory.ForwardClientManager; -import org.apache.rocketmq.remoting.exception.RemotingException; - -public class ForwardWriteConsumer extends AbstractForwardClient { - - private static final String CID_PREFIX = "CID_RMQ_PROXY_DELETE_MESSAGE_"; - - public ForwardWriteConsumer(ForwardClientManager clientFactory) { - super(clientFactory, CID_PREFIX); - } - - @Override - protected int getClientNum() { - return ConfigurationManager.getProxyConfig().getForwardConsumerNum(); - } - - @Override - protected MQClientAPIExt createNewClient(ForwardClientManager clientFactory, String name) { - double workerFactor = ConfigurationManager.getProxyConfig().getForwardConsumerWorkerFactor(); - final int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); - - return clientFactory.getMQClient(name, threadCount); - } - - public CompletableFuture ackMessage(Context ctx, String address, String messageId, AckMessageRequestHeader requestHeader) { - return this.ackMessage(ctx, address, messageId, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture ackMessage( - Context ctx, - String address, - String messageId, - AckMessageRequestHeader requestHeader, - long timeoutMillis - ) { - return this.getClient().ackMessageAsync(address, requestHeader, timeoutMillis); - } - - public CompletableFuture changeInvisibleTimeAsync( - Context ctx, - String address, - String brokerName, - String messageId, - ChangeInvisibleTimeRequestHeader requestHeader - ) { - return this.changeInvisibleTimeAsync(ctx, address, brokerName, messageId, requestHeader, DEFAULT_MQ_CLIENT_TIMEOUT); - } - - public CompletableFuture changeInvisibleTimeAsync( - Context ctx, - String address, - String brokerName, - String messageId, - ChangeInvisibleTimeRequestHeader requestHeader, - long timeoutMillis - ) { - return this.getClient().changeInvisibleTimeAsync(address, brokerName, requestHeader, timeoutMillis); - } - - public void updateConsumerOffsetOneWay( - Context ctx, - String brokerAddr, - UpdateConsumerOffsetRequestHeader header, - long timeoutMillis - ) throws RemotingException, InterruptedException { - this.getClient().updateConsumerOffsetOneWay(brokerAddr, header, timeoutMillis); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java deleted file mode 100644 index 35e4f696bf..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractClientManager.java +++ /dev/null @@ -1,86 +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.proxy.connector.factory; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.remoting.netty.NettyClientConfig; - -public abstract class AbstractClientManager { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected final ScheduledExecutorService scheduledExecutorService; - protected Map cacheTable = new ConcurrentHashMap<>(); - protected RPCHook rpcHook; - - public AbstractClientManager(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { - this.scheduledExecutorService = scheduledExecutorService; - this.rpcHook = rpcHook; - } - - protected abstract T newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads); - - protected abstract boolean tryStart(T t); - - protected abstract void shutdown(T t); - - protected static NettyClientConfig createNettyClientConfig(int bootstrapWorkerThreads) { - NettyClientConfig nettyClientConfig = new NettyClientConfig(); - nettyClientConfig.setBootstrapWorkerThreads(bootstrapWorkerThreads); - nettyClientConfig.setDisableNettyWorkerGroup(true); - nettyClientConfig.setDisableCallbackExecutor(true); - return nettyClientConfig; - } - - public T getOne(String instanceName, int bootstrapWorkerThreads) { - if (cacheTable.containsKey(instanceName)) { - return cacheTable.get(instanceName); - } - - T object; - try { - object = this.newOne(instanceName, rpcHook, bootstrapWorkerThreads); - } catch (Throwable t) { - throw new RuntimeException(t); - } - T old = cacheTable.putIfAbsent(instanceName, object); - if (old == null) { - if (!this.tryStart(object)) { - return null; - } - } else { - object = old; - } - - return object; - } - - public void shutdownAll() { - this.cacheTable.forEach((k, v) -> { - try { - this.shutdown(v); - } catch (Exception e) { - log.warn("try to shutdown client err.", e); - } - }); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java deleted file mode 100644 index 37a0cedabc..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/AbstractMQClientFactory.java +++ /dev/null @@ -1,66 +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.proxy.connector.factory; - -import java.time.Duration; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.client.impl.ClientRemotingProcessor; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.remoting.RPCHook; - -public abstract class AbstractMQClientFactory extends AbstractClientManager { - - public AbstractMQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { - super(scheduledExecutorService, rpcHook); - } - - protected abstract ClientRemotingProcessor createClientRemotingProcessor(); - - @Override - protected MQClientAPIExt newOne(String instanceName, RPCHook rpcHook, int bootstrapWorkerThreads) { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.setInstanceName(instanceName); - - return new MQClientAPIExt( - clientConfig, - createNettyClientConfig(bootstrapWorkerThreads), - createClientRemotingProcessor(), - rpcHook - ); - } - - @Override - protected boolean tryStart(MQClientAPIExt client) { - if (!client.updateNameServerAddressList()) { - this.scheduledExecutorService.scheduleAtFixedRate( - client::fetchNameServerAddr, - Duration.ofSeconds(10).toMillis(), - Duration.ofMinutes(2).toMillis(), - TimeUnit.MILLISECONDS - ); - } - client.start(); - return true; - } - - @Override - protected void shutdown(MQClientAPIExt client) { - client.shutdown(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java deleted file mode 100644 index af75583b0c..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/ForwardClientManager.java +++ /dev/null @@ -1,86 +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.proxy.connector.factory; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.ClientConfig; -import org.apache.rocketmq.proxy.connector.client.MQClientAPIExt; -import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.remoting.RPCHook; - -public class ForwardClientManager implements StartAndShutdown { - - protected RPCHook rpcHook; - - protected MQClientFactory mqClientFactory; - protected TransactionProducerFactory transactionalProducerFactory; - - public ForwardClientManager(TransactionStateChecker transactionStateChecker) { - this.init(transactionStateChecker); - } - - public ForwardClientManager(TransactionStateChecker transactionStateChecker, RPCHook rpcHook) { - this.rpcHook = rpcHook; - this.init(transactionStateChecker); - } - - protected void init(TransactionStateChecker transactionStateChecker) { - System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, - System.getProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); - if (StringUtils.isEmpty(ConfigurationManager.getProxyConfig().getNameSrvDomain())) { - String nameSrvAddr = ConfigurationManager.getProxyConfig().getNameSrvAddr(); - if (StringUtils.isEmpty(nameSrvAddr)) { - throw new IllegalArgumentException("the address of namesrv cannot be empty"); - } - System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, nameSrvAddr); - } else { - System.setProperty("rocketmq.namesrv.domain", ConfigurationManager.getProxyConfig().getNameSrvDomain()); - System.setProperty("rocketmq.namesrv.domain.subgroup", ConfigurationManager.getProxyConfig().getNameSrvDomainSubgroup()); - } - - ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat("ForwardClientFactoryScheduledThread" + "-%d").build() - ); - this.mqClientFactory = new MQClientFactory(scheduledExecutorService, this.rpcHook); - this.transactionalProducerFactory = new TransactionProducerFactory(scheduledExecutorService, this.rpcHook, transactionStateChecker); - } - - public MQClientAPIExt getMQClient(String instanceName, int bootstrapWorkerThreads) { - return mqClientFactory.getOne(instanceName, bootstrapWorkerThreads); - } - - public MQClientAPIExt getTransactionalProducer(String instanceName, int bootstrapWorkerThreads) { - return transactionalProducerFactory.getOne(instanceName, bootstrapWorkerThreads); - } - - @Override - public void start() throws Exception { - - } - - @Override - public void shutdown() throws Exception { - this.mqClientFactory.shutdownAll(); - this.transactionalProducerFactory.shutdownAll(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java deleted file mode 100644 index 60234b3f84..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/TransactionProducerFactory.java +++ /dev/null @@ -1,38 +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.proxy.connector.factory; - -import java.util.concurrent.ScheduledExecutorService; -import org.apache.rocketmq.client.impl.ClientRemotingProcessor; -import org.apache.rocketmq.proxy.connector.processor.ProxyClientRemotingProcessor; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.remoting.RPCHook; - -public class TransactionProducerFactory extends AbstractMQClientFactory { - protected final TransactionStateChecker transactionStateChecker; - - public TransactionProducerFactory(ScheduledExecutorService scheduledExecutorService, - RPCHook rpcHook, TransactionStateChecker transactionStateChecker) { - super(scheduledExecutorService, rpcHook); - this.transactionStateChecker = transactionStateChecker; - } - - @Override - protected ClientRemotingProcessor createClientRemotingProcessor() { - return new ProxyClientRemotingProcessor(this.transactionStateChecker); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java deleted file mode 100644 index c5269e64f9..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionStateCheckRequest.java +++ /dev/null @@ -1,103 +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.proxy.connector.transaction; - -import org.apache.rocketmq.common.message.MessageExt; - -public class TransactionStateCheckRequest { - private String groupId; - private Long tranStateTableOffset; - private Long commitLogOffset; - private String msgId; - private TransactionId transactionId; - private String brokerName; - private MessageExt messageExt; - - public TransactionStateCheckRequest( - String groupId, - Long tranStateTableOffset, - Long commitLogOffset, - String msgId, - TransactionId transactionId, - String brokerName, - MessageExt messageExt - ) { - this.groupId = groupId; - this.tranStateTableOffset = tranStateTableOffset; - this.commitLogOffset = commitLogOffset; - this.msgId = msgId; - this.transactionId = transactionId; - this.brokerName = brokerName; - this.messageExt = messageExt; - } - - public String getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public Long getTranStateTableOffset() { - return tranStateTableOffset; - } - - public void setTranStateTableOffset(Long tranStateTableOffset) { - this.tranStateTableOffset = tranStateTableOffset; - } - - public Long getCommitLogOffset() { - return commitLogOffset; - } - - public void setCommitLogOffset(Long commitLogOffset) { - this.commitLogOffset = commitLogOffset; - } - - public String getMsgId() { - return msgId; - } - - public void setMsgId(String msgId) { - this.msgId = msgId; - } - - public TransactionId getTransactionId() { - return transactionId; - } - - public void setTransactionId(TransactionId transactionId) { - this.transactionId = transactionId; - } - - public String getBrokerName() { - return brokerName; - } - - public void setBrokerName(String brokerName) { - this.brokerName = brokerName; - } - - public MessageExt getMessageExt() { - return messageExt; - } - - public void setMessageExt(MessageExt messageExt) { - this.messageExt = messageExt; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index d3c3063252..409c2c8c16 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -32,7 +32,6 @@ import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.MetadataHeader; import org.apache.rocketmq.acl.plain.PlainAccessResource; -import org.apache.rocketmq.proxy.grpc.v2.adapter.RequestMapping; public class AuthenticationInterceptor implements ServerInterceptor { private final List accessValidatorList; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/RequestMapping.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/RequestMapping.java new file mode 100644 index 0000000000..a9674d1837 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/RequestMapping.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.interceptor; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.SendMessageRequest; +import java.util.HashMap; +import java.util.Map; +import org.apache.rocketmq.common.protocol.RequestCode; + +public class RequestMapping { + private final static Map REQUEST_MAP = new HashMap() { + { + // v2 + put(QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); + put(SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); + put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); + put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); + put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); + put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); + put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); + put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); + } + }; + + public static int map(String rpcFullName) { + if (REQUEST_MAP.containsKey(rpcFullName)) { + return REQUEST_MAP.get(rpcFullName); + } + return RequestCode.HEART_BEAT; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java new file mode 100644 index 0000000000..925d36ae37 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2; + +import io.grpc.Context; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +public abstract class AbstractMessingActivity { + + protected final MessagingProcessor messagingProcessor; + protected final GrpcClientSettingsManager grpcClientSettingsManager; + + public AbstractMessingActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + this.messagingProcessor = messagingProcessor; + this.grpcClientSettingsManager = grpcClientSettingsManager; + } + + protected ProxyContext createContext(Context ctx) { + return ProxyContext.create() + .withVal(GrpcContextConstants.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) + .withVal(GrpcContextConstants.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE))); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java new file mode 100644 index 0000000000..57f5390080 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -0,0 +1,154 @@ +/* + * 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.grpc.v2; + +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.grpc.v2.client.ClientActivity; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.grpc.v2.consumer.AckMessageActivity; +import org.apache.rocketmq.proxy.grpc.v2.consumer.ChangeInvisibleDurationActivity; +import org.apache.rocketmq.proxy.grpc.v2.consumer.ReceiveMessageActivity; +import org.apache.rocketmq.proxy.grpc.v2.producer.ForwardMessageToDLQActivity; +import org.apache.rocketmq.proxy.grpc.v2.producer.SendMessageActivity; +import org.apache.rocketmq.proxy.grpc.v2.route.RouteActivity; +import org.apache.rocketmq.proxy.grpc.v2.transaction.EndTransactionActivity; +import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.service.ServiceManager; + +public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + private final ServiceManager serviceManager; + private GrpcClientSettingsManager grpcClientSettingsManager; + + private final ReceiveMessageActivity receiveMessageActivity; + private final AckMessageActivity ackMessageActivity; + private final ChangeInvisibleDurationActivity changeInvisibleDurationActivity; + private final SendMessageActivity sendMessageActivity; + private final ForwardMessageToDLQActivity forwardMessageToDLQActivity; + private final EndTransactionActivity endTransactionActivity; + private final RouteActivity routeActivity; + private final ClientActivity clientActivity; + + private final MessagingProcessor messagingProcessor; + + protected DefaultGrpcMessingActivity(ServiceManager serviceManager) { + this.serviceManager = serviceManager; + this.grpcClientSettingsManager = new GrpcClientSettingsManager(); + + this.messagingProcessor = new DefaultMessagingProcessor(serviceManager); + + this.receiveMessageActivity = new ReceiveMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.ackMessageActivity = new AckMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.sendMessageActivity = new SendMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.endTransactionActivity = new EndTransactionActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.routeActivity = new RouteActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + protected void init() { + this.appendStartAndShutdown(serviceManager); + } + + @Override + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + return this.routeActivity.queryRoute(ctx, request); + } + + @Override + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + return this.clientActivity.heartbeat(ctx, request); + } + + @Override + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + return this.sendMessageActivity.sendMessage(ctx, request); + } + + @Override + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + return this.routeActivity.queryAssignment(ctx, request); + } + + @Override + public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { + this.receiveMessageActivity.receiveMessage(ctx, request, responseObserver); + } + + @Override + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + return this.ackMessageActivity.ackMessage(ctx, request); + } + + @Override + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + return this.forwardMessageToDLQActivity.forwardMessageToDeadLetterQueue(ctx, request); + } + + @Override + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + return this.endTransactionActivity.endTransaction(ctx, request); + } + + @Override + public CompletableFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request) { + return this.clientActivity.notifyClientTermination(ctx, request); + } + + @Override + public CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + return this.changeInvisibleDurationActivity.changeInvisibleDuration(ctx, request); + } + + @Override + public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + return this.clientActivity.telemetry(ctx, responseObserver); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java similarity index 71% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java index 90648fe2cd..061766c0eb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/WriteQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java @@ -14,13 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.grpc.v2; -import apache.rocketmq.v2.SendMessageRequest; -import io.grpc.Context; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +public class GrpcContextConstants { -public interface WriteQueueSelector { - - SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request); + public static final String CLIENT_ID = "client_id"; + public static final String LANGUAGE = "language"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java similarity index 78% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 89666c1a80..6449259802 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -43,16 +43,23 @@ import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; +import org.apache.rocketmq.proxy.service.ServiceManager; -public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServiceImplBase { +public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServiceImplBase implements StartAndShutdown { - private final GrpcForwardService grpcForwardService; + private final GrpcMessingActivity grpcMessingActivity; - public GrpcMessagingProcessor(GrpcForwardService grpcForwardService) { - this.grpcForwardService = grpcForwardService; + protected GrpcMessagingApplication(GrpcMessingActivity grpcMessingActivity) { + this.grpcMessingActivity = grpcMessingActivity; + } + + public static GrpcMessagingApplication create(ServiceManager serviceManager) { + return new GrpcMessagingApplication(new DefaultGrpcMessingActivity( + serviceManager + )); } protected Status convertExceptionToStatus(Throwable t) { @@ -61,7 +68,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryRoute(Context.current(), request); + CompletableFuture future = grpcMessingActivity.queryRoute(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -74,7 +81,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.heartbeat(Context.current(), request); + CompletableFuture future = grpcMessingActivity.heartbeat(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -87,7 +94,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.sendMessage(Context.current(), request); + CompletableFuture future = grpcMessingActivity.sendMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -101,7 +108,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.queryAssignment(Context.current(), request); + CompletableFuture future = grpcMessingActivity.queryAssignment(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -114,12 +121,12 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - grpcForwardService.receiveMessage(Context.current(), request, responseObserver); + grpcMessingActivity.receiveMessage(Context.current(), request, responseObserver); } @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.ackMessage(Context.current(), request); + CompletableFuture future = grpcMessingActivity.ackMessage(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -133,7 +140,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.forwardMessageToDeadLetterQueue(Context.current(), request); + CompletableFuture future = grpcMessingActivity.forwardMessageToDeadLetterQueue(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -146,7 +153,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.endTransaction(Context.current(), request); + CompletableFuture future = grpcMessingActivity.endTransaction(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -160,7 +167,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.notifyClientTermination(Context.current(), request); + CompletableFuture future = grpcMessingActivity.notifyClientTermination(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -174,7 +181,7 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcForwardService.changeInvisibleDuration(Context.current(), request); + CompletableFuture future = grpcMessingActivity.changeInvisibleDuration(Context.current(), request); future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) .exceptionally(e -> { ResponseWriter.write( @@ -187,6 +194,16 @@ public class GrpcMessagingProcessor extends MessagingServiceGrpc.MessagingServic @Override public StreamObserver telemetry(StreamObserver responseObserver) { - return grpcForwardService.telemetry(Context.current(), responseObserver); + return grpcMessingActivity.telemetry(Context.current(), responseObserver); + } + + @Override + public void shutdown() throws Exception { + this.grpcMessingActivity.shutdown(); + } + + @Override + public void start() throws Exception { + this.grpcMessingActivity.start(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java index 3f0b459612..68337cba1c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcForwardService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service; +package org.apache.rocketmq.proxy.grpc.v2; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; @@ -43,7 +43,7 @@ import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.StartAndShutdown; -public interface GrpcForwardService extends StartAndShutdown { +public interface GrpcMessingActivity extends StartAndShutdown { CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java deleted file mode 100644 index 52fb47d950..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/GrpcConverter.java +++ /dev/null @@ -1,733 +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.proxy.grpc.v2.adapter; - -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Digest; -import apache.rocketmq.v2.DigestType; -import apache.rocketmq.v2.Encoding; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.FilterType; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.MessageType; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.Permission; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.SubscriptionEntry; -import apache.rocketmq.v2.SystemProperties; -import apache.rocketmq.v2.TransactionResolution; -import apache.rocketmq.v2.TransactionSource; -import apache.rocketmq.v2.VerifyMessageResult; -import com.google.common.collect.Maps; -import com.google.protobuf.ByteString; -import com.google.protobuf.Duration; -import com.google.protobuf.Timestamp; -import com.google.protobuf.util.Durations; -import com.google.protobuf.util.Timestamps; -import io.grpc.Context; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.constant.ConsumeInitMode; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.constant.PermName; -import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.filter.ExpressionType; -import org.apache.rocketmq.common.filter.FilterAPI; -import org.apache.rocketmq.common.message.MessageAccessor; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.NamespaceUtil; -import org.apache.rocketmq.common.protocol.body.CMResult; -import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; -import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.common.utils.BinaryUtil; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; - -public class GrpcConverter { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - public static String wrapResourceWithNamespace(Resource resource) { - return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); - } - - public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, - Settings clientSettings) { - HeartbeatData heartbeatData = new HeartbeatData(); - heartbeatData.setClientID(clientId); - switch (clientSettings.getClientType()) { - case PRODUCER: { - Set producerDataSet = new HashSet<>(); - for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = wrapResourceWithNamespace(topic); - producerDataSet.add(buildProducerData(topicName)); - } - heartbeatData.setProducerDataSet(producerDataSet); - break; - } - case PUSH_CONSUMER: - case SIMPLE_CONSUMER: { - String groupName = wrapResourceWithNamespace(request.getGroup()); - Set consumerDataSet = new HashSet<>(); - consumerDataSet.add(buildConsumerData(groupName, clientSettings)); - heartbeatData.setConsumerDataSet(consumerDataSet); - break; - } - } - return heartbeatData; - } - - public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(String groupName) { - org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData - = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); - buildProducerData.setGroupName(groupName); - return buildProducerData; - } - - public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, - Settings clientSettings) { - org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); - buildConsumerData.setGroupName(groupName); - buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); - - buildConsumerData.setMessageModel(MessageModel.CLUSTERING); - buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); - Set subscriptionDataSet = - buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()); - buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); - return buildConsumerData; - } - - public static ConsumeType buildConsumeType(ClientType clientType) { - switch (clientType) { - case SIMPLE_CONSUMER: - return ConsumeType.CONSUME_ACTIVELY; - case PUSH_CONSUMER: - return ConsumeType.CONSUME_PASSIVELY; - default: - throw new IllegalArgumentException("Client type is not consumer, type: " + clientType); - } - } - - public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, - String producerGroup, int queueId) { - SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); - - if (request.getMessagesCount() <= 0) { - throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); - } - if (request.getMessagesCount() > 1) { - requestHeader.setBatch(true); - } - Message message = request.getMessages(0); - SystemProperties systemProperties = message.getSystemProperties(); - - Map property = buildMessageProperty(message, producerGroup); - requestHeader.setProducerGroup(producerGroup); - requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); - requestHeader.setDefaultTopic(""); - requestHeader.setDefaultTopicQueueNums(0); - requestHeader.setQueueId(queueId); - // sysFlag (body encoding & message type) - int sysFlag = 0; - Encoding bodyEncoding = systemProperties.getBodyEncoding(); - if (bodyEncoding.equals(Encoding.GZIP)) { - sysFlag |= MessageSysFlag.COMPRESSED_FLAG; - } - // transaction - MessageType messageType = systemProperties.getMessageType(); - if (messageType.equals(MessageType.TRANSACTION)) { - sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; - } - requestHeader.setSysFlag(sysFlag); - requestHeader.setBornTimestamp(Timestamps.toMillis(systemProperties.getBornTimestamp())); - requestHeader.setFlag(0); - requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); - requestHeader.setReconsumeTimes(systemProperties.getDeliveryAttempt()); - - return requestHeader; - } - - public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime, boolean isFifo) { - Resource group = request.getGroup(); - String groupName = GrpcConverter.wrapResourceWithNamespace(group); - MessageQueue messageQueue = request.getMessageQueue(); - Resource topic = messageQueue.getTopic(); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - int queueId = messageQueue.getId(); - int maxMessageNumbers = request.getBatchSize(); - if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { - log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", - maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); - maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; - } - long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); - long bornTime = System.currentTimeMillis(); - - FilterExpression filterExpression = request.getFilterExpression(); - String expression = filterExpression.getExpression(); - String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); - - PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); - requestHeader.setConsumerGroup(groupName); - requestHeader.setTopic(topicName); - requestHeader.setQueueId(queueId); - requestHeader.setMaxMsgNums(maxMessageNumbers); - requestHeader.setInvisibleTime(invisibleTime); - requestHeader.setPollTime(pollTime); - requestHeader.setBornTime(bornTime); - requestHeader.setInitMode(ConsumeInitMode.MAX); - requestHeader.setExpType(expressionType); - requestHeader.setExp(expression); - requestHeader.setOrder(isFifo); - - return requestHeader; - } - - public static AckMessageRequestHeader buildAckMessageRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { - return buildAckMessageRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle); - } - - public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { - return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); - } - - public static AckMessageRequestHeader buildAckMessageRequestHeader(Resource topic, Resource group, ReceiptHandle handle) { - String groupName = GrpcConverter.wrapResourceWithNamespace(group); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - - AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); - ackMessageRequestHeader.setConsumerGroup(groupName); - ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - ackMessageRequestHeader.setQueueId(handle.getQueueId()); - ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); - ackMessageRequestHeader.setOffset(handle.getOffset()); - return ackMessageRequestHeader; - } - - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); - return changeInvisibleTimeRequestHeader; - } - - public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); - return changeInvisibleTimeRequestHeader; - } - - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(ReceiveMessageRequest request, - ReceiptHandle handle, String messageId, int maxReconsumeTimes) { - return buildConsumerSendMsgBackRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle, messageId, maxReconsumeTimes); - } - - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( - ForwardMessageToDeadLetterQueueRequest request) { - ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); - return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, - request.getMessageId(), request.getMaxDeliveryAttempts()); - } - - public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Resource topic, Resource group, ReceiptHandle handle, - String messageId, int maxReconsumeTimes) { - String groupName = GrpcConverter.wrapResourceWithNamespace(group); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); - consumerSendMsgBackRequestHeader.setGroup(groupName); - consumerSendMsgBackRequestHeader.setDelayLevel(-1); - consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); - consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); - consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); - return consumerSendMsgBackRequestHeader; - } - - public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, - String producerGroup) { - String messageId = request.getMessageId(); - String transactionId = request.getTransactionId(); - TransactionId handle; - try { - handle = TransactionId.decode(transactionId); - } catch (Exception e) { - throw new ProxyException(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); - } - long transactionStateTableOffset = handle.getTranStateTableOffset(); - long commitLogOffset = handle.getCommitLogOffset(); - boolean fromTransactionCheck = request.getSource() == TransactionSource.SOURCE_SERVER_CHECK; - int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); - - EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); - endTransactionRequestHeader.setProducerGroup(producerGroup); - endTransactionRequestHeader.setMsgId(messageId); - endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); - endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); - endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); - endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); - endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); - - return endTransactionRequestHeader; - } - - public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, - ClientType clientType, NotifyClientTerminationRequest request) { - UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - header.setClientID(clientId); - switch (clientType) { - case PRODUCER: { - header.setProducerGroup(groupName); - break; - } - case PUSH_CONSUMER: - case SIMPLE_CONSUMER: { - header.setConsumerGroup(groupName); - break; - } - } - return header; - } - - public static Map buildMessageProperty(Message message, String producerGroup) { - org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); - // set user properties - Map userProperties = message.getUserPropertiesMap(); - for (String key : userProperties.keySet()) { - if (MessageConst.STRING_HASH_SET.contains(key)) { - throw new ProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); - } - } - MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); - - // set tag - String tag = message.getSystemProperties().getTag(); - if (!"".equals(tag)) { - messageWithHeader.setTags(tag); - } - - // set keys - List keysList = message.getSystemProperties().getKeysList(); - if (keysList.size() > 0) { - messageWithHeader.setKeys(keysList); - } - - // set message id - String messageId = message.getSystemProperties().getMessageId(); - if ("".equals(messageId)) { - throw new ProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); - } - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); - - // set transaction property - MessageType messageType = message.getSystemProperties().getMessageType(); - if (messageType.equals(MessageType.TRANSACTION)) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); - - Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); - - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, - String.valueOf(Durations.toSeconds(transactionResolveDelay))); - } - - // set delay level or deliver timestamp - if (message.getSystemProperties().hasDeliveryTimestamp()) { - Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); - String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); - } - - // set reconsume times - int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); - MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); - // set producer group - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); - // set message group - String messageGroup = message.getSystemProperties().getMessageGroup(); - if (!messageGroup.isEmpty()) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); - } - // set trace context - String traceContext = message.getSystemProperties().getTraceContext(); - if (!traceContext.isEmpty()) { - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); - } - return messageWithHeader.getProperties(); - } - - public static List buildMessage(List protoMessageList, - Resource topic) { - String topicName = wrapResourceWithNamespace(topic); - List messages = new ArrayList<>(); - for (Message protoMessage : protoMessageList) { - if (!protoMessage.getTopic().equals(topic)) { - throw new ProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); - } - // here use topicName as producerGroup for transactional checker. - messages.add(buildMessage(protoMessage, topicName)); - } - return messages; - } - - public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage, String producerGroup) { - String topicName = wrapResourceWithNamespace(protoMessage.getTopic()); - - org.apache.rocketmq.common.message.Message message = - new org.apache.rocketmq.common.message.Message(topicName, protoMessage.getBody().toByteArray()); - Map messageProperty = buildMessageProperty(protoMessage, producerGroup); - - MessageAccessor.setProperties(message, messageProperty); - return message; - } - - public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { - Broker broker = Broker.getDefaultInstance(); - if (!StringUtils.isEmpty(brokerName)) { - broker = Broker.newBuilder() - .setName(brokerName) - .setId(0) - .build(); - } - return MessageQueue.newBuilder() - .setId(messageExt.getQueueId()) - .setTopic(Resource.newBuilder() - .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) - .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) - .build()) - .setBroker(broker) - .build(); - } - - public static String buildExpressionType(FilterType filterType) { - switch (filterType) { - case SQL: - return ExpressionType.SQL92; - case TAG: - default: - return ExpressionType.TAG; - } - } - - public static Set buildSubscriptionDataSet(List subscriptionEntryList) { - Set subscriptionDataSet = new HashSet<>(); - for (SubscriptionEntry sub : subscriptionEntryList) { - String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); - FilterExpression filterExpression = sub.getExpression(); - subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); - } - return subscriptionDataSet; - } - - public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { - String expression = filterExpression.getExpression(); - String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); - try { - return FilterAPI.build(topicName, expression, expressionType); - } catch (Exception e) { - throw new ProxyException(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); - } - } - - public static Message buildMessage(MessageExt messageExt) { - Map userProperties = buildUserAttributes(messageExt); - SystemProperties systemProperties = buildSystemProperties(messageExt); - Resource topic = buildResource(messageExt.getTopic()); - - return Message.newBuilder() - .setTopic(topic) - .putAllUserProperties(userProperties) - .setSystemProperties(systemProperties) - .setBody(ByteString.copyFrom(messageExt.getBody())) - .build(); - } - - protected static Map buildUserAttributes(MessageExt messageExt) { - Map userAttributes = new HashMap<>(); - Map properties = messageExt.getProperties(); - - for (Map.Entry property : properties.entrySet()) { - if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { - userAttributes.put(property.getKey(), property.getValue()); - } - } - - return userAttributes; - } - - protected static SystemProperties buildSystemProperties(MessageExt messageExt) { - SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); - - // tag - String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); - if (tag != null) { - systemPropertiesBuilder.setTag(tag); - } - - // keys - String keys = messageExt.getKeys(); - if (keys != null) { - String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); - systemPropertiesBuilder.addAllKeys(Arrays.asList(keysArray)); - } - - // message_id - String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - if (uniqKey != null) { - systemPropertiesBuilder.setMessageId(uniqKey); - } - - // body_digest & body_encoding - String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); - Digest digest = Digest.newBuilder() - .setType(DigestType.MD5) - .setChecksum(md5Result) - .build(); - systemPropertiesBuilder.setBodyDigest(digest); - - if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { - systemPropertiesBuilder.setBodyEncoding(Encoding.GZIP); - } else { - systemPropertiesBuilder.setBodyEncoding(Encoding.IDENTITY); - } - - // message_type - String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); - String isTransValue = "true"; - if (isTransValue.equals(isTrans)) { - systemPropertiesBuilder.setMessageType(MessageType.TRANSACTION); - } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { - systemPropertiesBuilder.setMessageType(MessageType.DELAY); - } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { - systemPropertiesBuilder.setMessageType(MessageType.FIFO); - } else { - systemPropertiesBuilder.setMessageType(MessageType.NORMAL); - } - - // born_timestamp (millis) - long bornTimestamp = messageExt.getBornTimestamp(); - systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); - - // born_host - systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); - - // store_timestamp (millis) - long storeTimestamp = messageExt.getStoreTimestamp(); - systemPropertiesBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); - - // store_host - SocketAddress storeHost = messageExt.getStoreHost(); - if (storeHost != null) { - systemPropertiesBuilder.setStoreHost(storeHost.toString()); - } - - // delivery_timestamp - String deliverMsString; - long deliverMs; - if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { - long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); - deliverMs = System.currentTimeMillis() + delayMs; - systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); - } else { - deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); - if (deliverMsString != null) { - deliverMs = Long.parseLong(deliverMsString); - systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); - } - } - - // sharding key - String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); - if (shardingKey != null) { - systemPropertiesBuilder.setMessageGroup(shardingKey); - } - - // receipt_handle && invisible_period - ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); - if (receiptHandle != null) { - systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); - } - - // partition_id - systemPropertiesBuilder.setQueueId(messageExt.getQueueId()); - - // partition_offset - systemPropertiesBuilder.setQueueOffset(messageExt.getQueueOffset()); - - // delivery_attempt - systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); - - // trace context - String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); - if (traceContext != null) { - systemPropertiesBuilder.setTraceContext(traceContext); - } - - return systemPropertiesBuilder.build(); - } - - public static int buildTransactionCommitOrRollback(TransactionResolution type) { - switch (type) { - case COMMIT: - return MessageSysFlag.TRANSACTION_COMMIT_TYPE; - case ROLLBACK: - return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; - default: - return MessageSysFlag.TRANSACTION_NOT_TYPE; - } - } - - public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { - ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); - switch (request.getStatus().getCode().getNumber()) { - case Code.OK_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); - break; - } - case Code.FAILED_TO_CONSUME_MESSAGE_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); - break; - } - case Code.MESSAGE_CORRUPTED_VALUE: { - consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); - break; - } - } - consumeMessageDirectlyResult.setRemark("From gRPC client"); - return consumeMessageDirectlyResult; - } - - public static Resource buildResource(String resourceNameWithNamespace) { - return Resource.newBuilder() - .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) - .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) - .build(); - } - - public static long buildPollTimeFromContext(Context ctx) { - long timeRemaining = ctx.getDeadline() - .timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - - return pollTime; - } - - public static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { - List messageQueueList = new ArrayList<>(); - - int r = 0; - int w = 0; - int rw = 0; - if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { - rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); - r = queueData.getReadQueueNums() - rw; - w = queueData.getWriteQueueNums() - rw; - } else if (PermName.isWriteable(queueData.getPerm())) { - w = queueData.getWriteQueueNums(); - } else if (PermName.isReadable(queueData.getPerm())) { - r = queueData.getReadQueueNums(); - } - - // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. - int queueIdIndex = 0; - for (int i = 0; i < r; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ) - .build(); - messageQueueList.add(messageQueue); - } - - for (int i = 0; i < w; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.WRITE) - .build(); - messageQueueList.add(messageQueue); - } - - for (int i = 0; i < rw; i++) { - MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) - .setId(queueIdIndex++) - .setPermission(Permission.READ_WRITE) - .build(); - messageQueueList.add(messageQueue); - } - - return messageQueueList; - } - -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java deleted file mode 100644 index a14dd4e3f8..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/GrpcClientChannel.java +++ /dev/null @@ -1,169 +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.proxy.grpc.v2.adapter.channel; - -import apache.rocketmq.v2.PrintThreadStackTraceCommand; -import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import io.netty.channel.ChannelFuture; -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; -import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class GrpcClientChannel extends SimpleChannel { - private final AtomicReference> telemetryCommandRef = new AtomicReference<>(); - - private final String group; - private final String clientId; - private final TelemetryCommandManager manager; - - private GrpcClientChannel(Context ctx, String group, String clientId, TelemetryCommandManager manager) { - super(ChannelManager.createSimpleChannelDirectly(ctx)); - this.group = group; - this.clientId = clientId; - this.manager = manager; - } - - public void setClientObserver(StreamObserver future) { - this.telemetryCommandRef.set(future); - } - - public static GrpcClientChannel create( - ChannelManager channelManager, - String group, - String clientId, - TelemetryCommandManager manager - ) { - return create(Context.current(), channelManager, group, clientId, manager); - } - - public static GrpcClientChannel create( - Context ctx, - ChannelManager channelManager, - String group, - String clientId, - TelemetryCommandManager manager - ) { - GrpcClientChannel channel = channelManager.createChannel( - ctx, - buildKey(group, clientId), - context -> new GrpcClientChannel(context, group, clientId, manager), - GrpcClientChannel.class - ); - - channelManager.addGroupClientId(group, clientId); - return channel; - } - - public static GrpcClientChannel getChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.getChannel(buildKey(group, clientId), GrpcClientChannel.class); - } - - public static GrpcClientChannel removeChannel(ChannelManager channelManager, String group, String clientId) { - return channelManager.removeChannel(buildKey(group, clientId), GrpcClientChannel.class); - } - - private static String buildKey(String group, String clientId) { - return group + "@" + clientId; - } - - @Override - public boolean isWritable() { - return this.telemetryCommandRef.get() != null; - } - - /** - * Write response to corresponding remote client - * - * @param msg Target write object, {@link RemotingCommand} or {@link TelemetryCommand} - * @return Always success {@link ChannelFuture} - *

- * Case {@link RequestCode#CHECK_TRANSACTION_STATE} - * @see org.apache.rocketmq.broker.client.net.Broker2Client#checkProducerTransactionState - *

- *

- * Case {@link RequestCode#GET_CONSUMER_RUNNING_INFO} - * @see org.apache.rocketmq.broker.processor.AdminBrokerProcessor - * getConsumerRunningInfo - *

- */ - @Override - public ChannelFuture writeAndFlush(Object msg) { - StreamObserver streamObserver = telemetryCommandRef.get(); - if (msg instanceof RemotingCommand) { - RemotingCommand command = (RemotingCommand) msg; - try { - switch (command.getCode()) { - case RequestCode.CHECK_TRANSACTION_STATE: { - final CheckTransactionStateRequestHeader header = (CheckTransactionStateRequestHeader) command.readCustomHeader(); - MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); - TransactionId transactionId = TransactionId.genByBrokerTransactionId(RemotingUtil.string2SocketAddress(localAddress), - header.getTransactionId(), messageExt.getCommitLogOffset(), messageExt.getQueueOffset()); - streamObserver.onNext(TelemetryCommand.newBuilder() - .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() - .setTransactionId(transactionId.getProxyTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) - .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, header.getBrokerName())) - .build()) - .build()); - break; - } - case RequestCode.GET_CONSUMER_RUNNING_INFO: { - final GetConsumerRunningInfoRequestHeader header = (GetConsumerRunningInfoRequestHeader) command.readCustomHeader(); - if (!header.isJstackEnable()) { - break; - } - String nonce = manager.putCommand(command.getOpaque()); - streamObserver.onNext(TelemetryCommand.newBuilder() - .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() - .setNonce(nonce) - .build()) - .build()); - break; - } - } - } catch (Exception ignore) { - } - } - if (msg instanceof TelemetryCommand) { - TelemetryCommand response = (TelemetryCommand) msg; - streamObserver.onNext(response); - } - return super.writeAndFlush(msg); - } - - public String getGroup() { - return group; - } - - public String getClientId() { - return clientId; - } -} 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 new file mode 100644 index 0000000000..1824104f6c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcChannelManager.java @@ -0,0 +1,84 @@ +/* + * 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.grpc.v2.channel; + +import io.grpc.Context; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; + +public class GrpcChannelManager { + private final ProxyOutService proxyOutService; + protected final ConcurrentMap/* clientId */> groupClientIdChannelMap = new ConcurrentHashMap<>(); + + protected final AtomicLong nonceIdGenerator = new AtomicLong(0); + protected final ConcurrentMap> resultNonceFutureMap = new ConcurrentHashMap<>(); + + public GrpcChannelManager(ProxyOutService proxyOutService) { + this.proxyOutService = proxyOutService; + } + + public GrpcClientChannel createChannel(Context ctx, String group, String clientId) { + this.groupClientIdChannelMap.compute(group, (groupKey, clientIdMap) -> { + if (clientIdMap == null) { + clientIdMap = new ConcurrentHashMap<>(); + } + clientIdMap.computeIfAbsent(clientId, clientIdKey -> new GrpcClientChannel(proxyOutService, this, ctx, group, clientId)); + return clientIdMap; + }); + return getChannel(group, clientId); + } + + public GrpcClientChannel getChannel(String group, String clientId) { + Map clientIdChannelMap = this.groupClientIdChannelMap.get(group); + if (clientIdChannelMap == null) { + return null; + } + return clientIdChannelMap.get(clientId); + } + + public GrpcClientChannel removeChannel(String group, String clientId) { + AtomicReference channelRef = new AtomicReference<>(); + this.groupClientIdChannelMap.computeIfPresent(group, (groupKey, clientIdMap) -> { + channelRef.set(clientIdMap.remove(clientId)); + if (clientIdMap.isEmpty()) { + return null; + } + return clientIdMap; + }); + return channelRef.get(); + } + + public String addResponseFuture(CompletableFuture responseFuture) { + String nonce = this.nextNonce(); + this.resultNonceFutureMap.put(nonce, responseFuture); + return nonce; + } + + public CompletableFuture getAndRemoveResponseFuture(String nonce) { + return (CompletableFuture) this.resultNonceFutureMap.remove(nonce); + } + + protected String nextNonce() { + return String.valueOf(this.nonceIdGenerator.getAndIncrement()); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java new file mode 100644 index 0000000000..1ad4422a0c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -0,0 +1,200 @@ +/* + * 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.grpc.v2.channel; + +import apache.rocketmq.v2.PrintThreadStackTraceCommand; +import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.VerifyMessageCommand; +import com.google.common.collect.ComparisonChain; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import io.netty.channel.ChannelId; +import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; +import org.apache.rocketmq.proxy.service.out.ProxyChannel; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class GrpcClientChannel extends ProxyChannel { + + protected static final String SEPARATOR = "@"; + + private final GrpcChannelManager grpcChannelManager; + + private final AtomicReference> telemetryCommandRef = new AtomicReference<>(); + private final String group; + private final String clientId; + private final String remoteAddress; + private final String localAddress; + + public GrpcClientChannel(ProxyOutService proxyOutService, GrpcChannelManager grpcChannelManager, Context ctx, String group, String clientId) { + super(proxyOutService, null, new GrpcChannelId(group, clientId)); + this.grpcChannelManager = grpcChannelManager; + this.remoteAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS); + this.localAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS); + this.group = group; + this.clientId = clientId; + } + + protected static class GrpcChannelId implements ChannelId { + + private final String group; + private final String clientId; + + public GrpcChannelId(String group, String clientId) { + this.group = group; + this.clientId = clientId; + } + + @Override + public String asShortText() { + return this.clientId; + } + + @Override + public String asLongText() { + return this.group + SEPARATOR + this.clientId; + } + + @Override + public int compareTo(ChannelId o) { + if (this == o) { + return 0; + } + if (o instanceof GrpcChannelId) { + GrpcChannelId other = (GrpcChannelId) o; + return ComparisonChain.start() + .compare(this.group, other.group) + .compare(this.clientId, other.clientId) + .result(); + } + + return asLongText().compareTo(o.asLongText()); + } + } + + public void setClientObserver(StreamObserver future) { + this.telemetryCommandRef.set(future); + } + + @Override + public boolean isOpen() { + return this.telemetryCommandRef.get() != null; + } + + @Override + public boolean isActive() { + return this.telemetryCommandRef.get() != null; + } + + @Override + public boolean isWritable() { + return this.telemetryCommandRef.get() != null; + } + + @Override + protected SocketAddress localAddress0() { + return RemotingUtil.string2SocketAddress(this.localAddress); + } + + @Override + protected SocketAddress remoteAddress0() { + return RemotingUtil.string2SocketAddress(this.remoteAddress); + } + + @Override + protected CompletableFuture processOtherMessage(Object msg) { + if (msg instanceof TelemetryCommand) { + TelemetryCommand response = (TelemetryCommand) msg; + this.getTelemetryCommandStreamObserver().onNext(response); + } + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, + MessageExt messageExt, TransactionId transactionId) { + this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() + .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() + .setTransactionId(transactionId.getProxyTransactionId()) + .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) + .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, header.getBrokerName())) + .build()) + .build()); + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + GetConsumerRunningInfoRequestHeader header, + CompletableFuture responseFuture) { + if (!header.isJstackEnable()) { + return CompletableFuture.completedFuture(null); + } + this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() + .setPrintThreadStackTraceCommand(PrintThreadStackTraceCommand.newBuilder() + .setNonce(this.grpcChannelManager.addResponseFuture(responseFuture)) + .build()) + .build()); + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processConsumeMessageDirectly(RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header, + MessageExt messageExt, CompletableFuture responseFuture) { + this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() + .setVerifyMessageCommand(VerifyMessageCommand.newBuilder() + .setNonce(this.grpcChannelManager.addResponseFuture(responseFuture)) + .setMessage(GrpcConverter.buildMessage(messageExt)) + .build()) + .build()); + return CompletableFuture.completedFuture(null); + } + + public String getGroup() { + return group; + } + + public String getClientId() { + return clientId; + } + + public String getRemoteAddress() { + return remoteAddress; + } + + public String getLocalAddress() { + return localAddress; + } + + public StreamObserver getTelemetryCommandStreamObserver() { + return this.telemetryCommandRef.get(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java new file mode 100644 index 0000000000..8e7c9699b7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -0,0 +1,360 @@ +/* + * 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.grpc.v2.client; + +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.SubscriptionEntry; +import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.ThreadStackTrace; +import apache.rocketmq.v2.VerifyMessageResult; +import io.grpc.Context; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.StreamObserver; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.broker.client.ProducerGroupEvent; +import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.remoting.protocol.LanguageCode; + +public class ClientActivity extends AbstractMessingActivity { + + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + private final GrpcChannelManager grpcChannelManager; + + public ClientActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + + this.grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); + + this.init(); + } + + protected void init() { + this.messagingProcessor.registerConsumerListener(new ConsumerIdsChangeListenerImpl()); + this.messagingProcessor.registerProducerListener(new ProducerChangeListenerImpl()); + } + + public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + CompletableFuture future = new CompletableFuture<>(); + + try { + ProxyContext context = createContext(ctx); + String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); + LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); + + Settings clientSettings = grpcClientSettingsManager.getClientSettings(clientId); + switch (clientSettings.getClientType()) { + case PRODUCER: { + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + // use topic name as producer group + this.messagingProcessor.registerProducer(context, topicName, clientChannelInfo); + this.messagingProcessor.addTransactionSubscription(context, topicName, topicName); + } + break; + } + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: { + if (!request.hasGroup()) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); + } + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + + this.messagingProcessor.registerConsumer( + context, + consumerGroup, + clientChannelInfo, + this.buildConsumeType(clientSettings.getClientType()), + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + this.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()) + ); + break; + } + default: { + throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); + } + } + future.complete(HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + return future; + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { + CompletableFuture future = new CompletableFuture<>(); + + try { + ProxyContext context = createContext(ctx); + String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); + LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); + Settings clientSettings = grpcClientSettingsManager.getClientSettings(clientId); + + switch (clientSettings.getClientType()) { + case PRODUCER: + for (Resource topic : clientSettings.getPublishing().getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + // user topic name as producer group + GrpcClientChannel channel = this.grpcChannelManager.removeChannel(topicName, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + if (channel != null) { + this.messagingProcessor.unRegisterProducer(context, topicName, clientChannelInfo); + } + } + break; + case PUSH_CONSUMER: + case SIMPLE_CONSUMER: + if (!request.hasGroup()) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); + } + String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + GrpcClientChannel channel = this.grpcChannelManager.removeChannel(consumerGroup, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + if (channel != null) { + this.messagingProcessor.unRegisterConsumer(context, consumerGroup, clientChannelInfo); + } + break; + default: + break; + } + future.complete(NotifyClientTerminationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(TelemetryCommand request) { + switch (request.getCommandCase()) { + case SETTINGS: { + responseObserver.onNext(processClientSettings(ctx, request, responseObserver)); + break; + } + case THREAD_STACK_TRACE: { + reportThreadStackTrace(ctx, request.getThreadStackTrace()); + break; + } + case VERIFY_MESSAGE_RESULT: { + reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); + break; + } + default: { + ResponseWriter.writeException(responseObserver, new StatusRuntimeException( + Status.INVALID_ARGUMENT.withDescription("") + )); + } + } + } + + @Override + public void onError(Throwable t) { + log.error("telemetry on error", t); + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + }; + } + + protected TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { + ProxyContext context = createContext(ctx); + String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); + grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); + Settings settings = grpcClientSettingsManager.getClientSettings(clientId); + if (settings.hasPublishing()) { + for (Resource topic : settings.getPublishing().getTopicsList()) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + GrpcClientChannel producerChannel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); + producerChannel.setClientObserver(responseObserver); + } + } + if (settings.hasSubscription()) { + String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); + GrpcClientChannel consumerChannel = this.grpcChannelManager.createChannel(ctx, groupName, clientId); + consumerChannel.setClientObserver(responseObserver); + } + return TelemetryCommand.newBuilder() + .setSettings(settings) + .build(); + } + + protected void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { + String nonce = request.getNonce(); + String threadStack = request.getThreadStackTrace(); + CompletableFuture responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + if (responseFuture != null) { + try { + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(threadStack); + responseFuture.complete(runningInfo); + } catch (Throwable t) { + responseFuture.completeExceptionally(t); + } + } + } + + protected void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { + String nonce = request.getNonce(); + CompletableFuture responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + if (responseFuture != null) { + try { + ConsumeMessageDirectlyResult result = this.buildConsumeMessageDirectlyResult(request); + responseFuture.complete(result); + } catch (Throwable t) { + responseFuture.completeExceptionally(t); + } + } + } + + protected ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { + ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); + switch (request.getStatus().getCode().getNumber()) { + case Code.OK_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); + break; + } + case Code.FAILED_TO_CONSUME_MESSAGE_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); + break; + } + case Code.MESSAGE_CORRUPTED_VALUE: { + consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); + break; + } + } + consumeMessageDirectlyResult.setRemark("from gRPC client"); + return consumeMessageDirectlyResult; + } + + protected ConsumeType buildConsumeType(ClientType clientType) { + switch (clientType) { + case SIMPLE_CONSUMER: + return ConsumeType.CONSUME_ACTIVELY; + case PUSH_CONSUMER: + return ConsumeType.CONSUME_PASSIVELY; + default: + throw new IllegalArgumentException("Client type is not consumer, type: " + clientType); + } + } + + protected Set buildSubscriptionDataSet(List subscriptionEntryList) { + Set subscriptionDataSet = new HashSet<>(); + for (SubscriptionEntry sub : subscriptionEntryList) { + String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); + FilterExpression filterExpression = sub.getExpression(); + subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); + } + return subscriptionDataSet; + } + + protected SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { + String expression = filterExpression.getExpression(); + String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); + try { + return FilterAPI.build(topicName, expression, expressionType); + } catch (Exception e) { + throw new GrpcProxyException(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); + } + } + + protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { + + @Override + public void handle(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]; + grpcChannelManager.removeChannel(group, clientChannelInfo.getClientId()); + grpcClientSettingsManager.removeClientSettings(clientChannelInfo.getClientId()); + } + } + } + + @Override + public void shutdown() { + + } + } + + protected class ProducerChangeListenerImpl implements ProducerChangeListener { + + @Override + public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { + if (event == ProducerGroupEvent.CLIENT_UNREGISTER) { + grpcChannelManager.removeChannel(group, clientChannelInfo.getClientId()); + grpcClientSettingsManager.removeClientSettings(clientChannelInfo.getClientId()); + } + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java similarity index 89% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index e0088cd8b8..b5f8bde099 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/GrpcClientManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service; +package org.apache.rocketmq.proxy.grpc.v2.common; import apache.rocketmq.v2.ExponentialBackoff; import apache.rocketmq.v2.Publishing; @@ -23,13 +23,11 @@ import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; import com.google.protobuf.util.Durations; -import io.grpc.Context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -public class GrpcClientManager { +public class GrpcClientSettingsManager { // TODO: read config from topic or subscription configManager protected static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() @@ -63,11 +61,6 @@ public class GrpcClientManager { .build(); protected static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); - public Settings getClientSettings(Context ctx) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - return CLIENT_SETTINGS_MAP.get(clientId); - } - public Settings getClientSettings(String clientId) { return CLIENT_SETTINGS_MAP.get(clientId); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java new file mode 100644 index 0000000000..810708a216 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -0,0 +1,229 @@ +/* + * 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.grpc.v2.common; + +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Digest; +import apache.rocketmq.v2.DigestType; +import apache.rocketmq.v2.Encoding; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.MessageType; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SystemProperties; +import com.google.protobuf.ByteString; +import com.google.protobuf.util.Timestamps; +import java.net.SocketAddress; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.filter.ExpressionType; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.NamespaceUtil; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.common.utils.BinaryUtil; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; + +public class GrpcConverter { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + public static String wrapResourceWithNamespace(Resource resource) { + return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); + } + + public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { + Broker broker = Broker.getDefaultInstance(); + if (!StringUtils.isEmpty(brokerName)) { + broker = Broker.newBuilder() + .setName(brokerName) + .setId(0) + .build(); + } + return MessageQueue.newBuilder() + .setId(messageExt.getQueueId()) + .setTopic(Resource.newBuilder() + .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) + .build()) + .setBroker(broker) + .build(); + } + + public static String buildExpressionType(FilterType filterType) { + switch (filterType) { + case SQL: + return ExpressionType.SQL92; + case TAG: + default: + return ExpressionType.TAG; + } + } + + public static Message buildMessage(MessageExt messageExt) { + Map userProperties = buildUserAttributes(messageExt); + SystemProperties systemProperties = buildSystemProperties(messageExt); + Resource topic = buildResource(messageExt.getTopic()); + + return Message.newBuilder() + .setTopic(topic) + .putAllUserProperties(userProperties) + .setSystemProperties(systemProperties) + .setBody(ByteString.copyFrom(messageExt.getBody())) + .build(); + } + + protected static Map buildUserAttributes(MessageExt messageExt) { + Map userAttributes = new HashMap<>(); + Map properties = messageExt.getProperties(); + + for (Map.Entry property : properties.entrySet()) { + if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { + userAttributes.put(property.getKey(), property.getValue()); + } + } + + return userAttributes; + } + + protected static SystemProperties buildSystemProperties(MessageExt messageExt) { + SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); + + // tag + String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); + if (tag != null) { + systemPropertiesBuilder.setTag(tag); + } + + // keys + String keys = messageExt.getKeys(); + if (keys != null) { + String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); + systemPropertiesBuilder.addAllKeys(Arrays.asList(keysArray)); + } + + // message_id + String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); + if (uniqKey != null) { + systemPropertiesBuilder.setMessageId(uniqKey); + } + + // body_digest & body_encoding + String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); + Digest digest = Digest.newBuilder() + .setType(DigestType.MD5) + .setChecksum(md5Result) + .build(); + systemPropertiesBuilder.setBodyDigest(digest); + + if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { + systemPropertiesBuilder.setBodyEncoding(Encoding.GZIP); + } else { + systemPropertiesBuilder.setBodyEncoding(Encoding.IDENTITY); + } + + // message_type + String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + String isTransValue = "true"; + if (isTransValue.equals(isTrans)) { + systemPropertiesBuilder.setMessageType(MessageType.TRANSACTION); + } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + systemPropertiesBuilder.setMessageType(MessageType.DELAY); + } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { + systemPropertiesBuilder.setMessageType(MessageType.FIFO); + } else { + systemPropertiesBuilder.setMessageType(MessageType.NORMAL); + } + + // born_timestamp (millis) + long bornTimestamp = messageExt.getBornTimestamp(); + systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); + + // born_host + systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); + + // store_timestamp (millis) + long storeTimestamp = messageExt.getStoreTimestamp(); + systemPropertiesBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); + + // store_host + SocketAddress storeHost = messageExt.getStoreHost(); + if (storeHost != null) { + systemPropertiesBuilder.setStoreHost(storeHost.toString()); + } + + // delivery_timestamp + String deliverMsString; + long deliverMs; + if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); + deliverMs = System.currentTimeMillis() + delayMs; + systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } else { + deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); + if (deliverMsString != null) { + deliverMs = Long.parseLong(deliverMsString); + systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); + } + } + + // sharding key + String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); + if (shardingKey != null) { + systemPropertiesBuilder.setMessageGroup(shardingKey); + } + + // receipt_handle && invisible_period + ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); + if (receiptHandle != null) { + systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); + } + + // partition_id + systemPropertiesBuilder.setQueueId(messageExt.getQueueId()); + + // partition_offset + systemPropertiesBuilder.setQueueOffset(messageExt.getQueueOffset()); + + // delivery_attempt + systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); + + // trace context + String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); + if (traceContext != null) { + systemPropertiesBuilder.setTraceContext(traceContext); + } + + return systemPropertiesBuilder.build(); + } + + public static Resource buildResource(String resourceNameWithNamespace) { + return Resource.newBuilder() + .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) + .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java new file mode 100644 index 0000000000..702ca2c75d --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.common; + +import apache.rocketmq.v2.Code; +import java.util.HashMap; +import java.util.Map; +import org.apache.rocketmq.proxy.common.ProxyException; +import org.apache.rocketmq.proxy.common.ProxyExceptionCode; + +public class GrpcProxyException extends RuntimeException { + + private ProxyException proxyException; + private Code code; + + private static final Map CODE_MAPPING = new HashMap<>(); + + static { + CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.INVALID_RECEIPT_HANDLE); + CODE_MAPPING.put(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, Code.RECEIPT_HANDLE_EXPIRED); + CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); + } + + public GrpcProxyException(Code code, String message) { + super(message); + this.code = code; + } + + public GrpcProxyException(Code code, String message, Throwable t) { + super(message, t); + this.code = code; + } + + public GrpcProxyException(ProxyException proxyException) { + super(proxyException); + this.proxyException = proxyException; + } + + public Code getCode() { + if (this.code != null) { + return this.code; + } + if (this.proxyException != null) { + return CODE_MAPPING.getOrDefault(this.proxyException.getCode(), Code.INTERNAL_SERVER_ERROR); + } + return Code.INTERNAL_SERVER_ERROR; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java similarity index 88% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java index 0344f28193..c0c275f5b5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java @@ -15,28 +15,32 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.adapter; +package org.apache.rocketmq.proxy.grpc.v2.common; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Status; -import java.util.concurrent.CompletionException; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.ProxyException; +import org.apache.rocketmq.proxy.common.utils.ExceptionUtils; public class ResponseBuilder { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); public static Status buildStatus(Throwable t) { - if (t instanceof CompletionException) { - t = t.getCause(); - } + t = ExceptionUtils.getRealException(t); + if (t instanceof ProxyException) { - ProxyException proxyException = (ProxyException) t; - return ResponseBuilder.buildStatus(proxyException.getCode(), proxyException.getMessage()); + t = new GrpcProxyException((ProxyException) t); } + if (t instanceof GrpcProxyException) { + GrpcProxyException grpcProxyException = (GrpcProxyException) t; + return ResponseBuilder.buildStatus(grpcProxyException.getCode(), grpcProxyException.getMessage()); + } + log.error("internal server error", t); return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java index 90f1bfaa77..1f63734932 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.adapter; +package org.apache.rocketmq.proxy.grpc.v2.common; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; 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 new file mode 100644 index 0000000000..7226717a73 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java @@ -0,0 +1,118 @@ +/* + * 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.grpc.v2.consumer; + +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 io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.MessagingProcessor; + +public class AckMessageActivity extends AbstractMessingActivity { + + public AckMessageActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + ProxyContext proxyContext = createContext(ctx); + CompletableFuture future = new CompletableFuture<>(); + + try { + CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; + for (int i = 0; i < request.getEntriesCount(); i++) { + futures[i] = processAckMessage(proxyContext, request, request.getEntries(i)); + } + CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { + if (throwable != null) { + future.completeExceptionally(throwable); + return; + } + List entryList = new ArrayList<>(); + for (CompletableFuture entryFuture : futures) { + entryFuture.thenAccept(entryList::add); + } + AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllEntries(entryList); + future.complete(responseBuilder.build()); + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected CompletableFuture processAckMessage(ProxyContext ctx, AckMessageRequest request, + AckMessageEntry ackMessageEntry) { + CompletableFuture future = new CompletableFuture<>(); + AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()); + + try { + ReceiptHandle receiptHandle = ReceiptHandle.decode(ackMessageEntry.getReceiptHandle()); + + CompletableFuture ackResultFuture = this.messagingProcessor.ackMessage( + ctx, + receiptHandle, + ackMessageEntry.getMessageId(), + GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + ackResultFuture + .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) + .exceptionally(throwable -> { + future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); + return null; + }); + } catch (Throwable t) { + future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); + } + return future; + } + + protected AckMessageResultEntry convertToAckMessageResultEntry(ProxyContext ctx, AckMessageEntry ackMessageEntry, + AckResult ackResult) { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return AckMessageResultEntry.newBuilder() + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build(); + } + return AckMessageResultEntry.newBuilder() + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()) + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java new file mode 100644 index 0000000000..fc8fb405f7 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -0,0 +1,76 @@ +/* + * 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.grpc.v2.consumer; + +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.Code; +import com.google.protobuf.util.Durations; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.MessagingProcessor; + +public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { + + public ChangeInvisibleDurationActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request) { + ProxyContext context = createContext(ctx); + CompletableFuture future = new CompletableFuture<>(); + + try { + ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); + + return this.messagingProcessor.changeInvisibleTime( + context, + receiptHandle, + request.getMessageId(), + GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.wrapResourceWithNamespace(request.getTopic()), + Durations.toMillis(request.getInvisibleDuration()) + ).thenApply(ackResult -> convertToChangeInvisibleDurationResponse(context, request, ackResult)); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected ChangeInvisibleDurationResponse convertToChangeInvisibleDurationResponse(ProxyContext ctx, + ChangeInvisibleDurationRequest request, AckResult ackResult) { + if (AckStatus.OK.equals(ackResult.getStatus())) { + return ChangeInvisibleDurationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setReceiptHandle(ackResult.getExtraInfo()) + .build(); + } + return ChangeInvisibleDurationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) + .build(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java new file mode 100644 index 0000000000..23842c6fab --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.consumer; + +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.utils.FilterUtils; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; +import org.apache.rocketmq.proxy.processor.PopMessageResultFilter; + +public class PopMessageResultFilterImpl implements PopMessageResultFilter { + + private final GrpcClientSettingsManager grpcClientSettingsManager; + + public PopMessageResultFilterImpl(GrpcClientSettingsManager manager) { + grpcClientSettingsManager = manager; + } + + @Override + public FilterResult filterMessage(ProxyContext ctx, String consumerGroup, SubscriptionData subscriptionData, MessageExt messageExt) { + int maxAttempts = grpcClientSettingsManager.getClientSettings(ctx.getVal(GrpcContextConstants.CLIENT_ID)).getBackoffPolicy().getMaxAttempts(); + if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { + return FilterResult.NO_MATCH; + } + if (messageExt.getReconsumeTimes() >= maxAttempts) { + return FilterResult.TO_DLQ; + } + return FilterResult.MATCH; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java new file mode 100644 index 0000000000..bac4e3cc44 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.consumer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import com.google.protobuf.util.Durations; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.constant.ConsumeInitMode; +import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +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.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.QueueSelector; +import org.apache.rocketmq.proxy.service.route.MessageQueueSelector; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; + +public class ReceiveMessageActivity extends AbstractMessingActivity { + + public ReceiveMessageActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public void receiveMessage(Context ctx, ReceiveMessageRequest request, + StreamObserver responseObserver) { + ProxyContext proxyContext = createContext(ctx); + boolean fifo = false; + + ReceiveMessageResponseStreamWriter writer = new ReceiveMessageResponseStreamWriter( + this.messagingProcessor, + responseObserver + ); + + long timeRemaining = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + if (pollTime <= 0) { + writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "no new message"); + return; + } + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + FilterExpression filterExpression = request.getFilterExpression(); + SubscriptionData subscriptionData; + try { + subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), + GrpcConverter.buildExpressionType(filterExpression.getType())); + } catch (Exception e) { + writer.write(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); + return; + } + + this.messagingProcessor.popMessage( + proxyContext, + new ReceiveMessageQueueSelector( + request.getMessageQueue().getBroker().getName() + ), + group, + topic, + request.getBatchSize(), + Durations.toMillis(request.getInvisibleDuration()), + pollTime, + ConsumeInitMode.MAX, + subscriptionData, + fifo, + new PopMessageResultFilterImpl(grpcClientSettingsManager), + timeRemaining + ).thenAccept(popResult -> writer.write(proxyContext, request, popResult)) + .exceptionally(t -> { + writer.write(proxyContext, request, t); + return null; + }); + } + + protected static class ReceiveMessageQueueSelector implements QueueSelector { + + private final String brokerName; + + public ReceiveMessageQueueSelector(String brokerName) { + this.brokerName = brokerName; + } + + @Override + public SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { + try { + SelectableMessageQueue selectableMessageQueue = null; + MessageQueueSelector messageQueueSelector = messageQueueView.getReadSelector(); + + if (StringUtils.isNotBlank(brokerName)) { + selectableMessageQueue = messageQueueSelector.getQueueByBrokerName(brokerName); + } + + if (selectableMessageQueue == null) { + selectableMessageQueue = messageQueueSelector.selectOne(true); + } + return selectableMessageQueue; + } catch (Throwable t) { + return null; + } + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..6a94f49848 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.consumer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import io.grpc.stub.StreamObserver; +import java.time.Duration; +import java.util.Iterator; +import java.util.List; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; + +public class ReceiveMessageResponseStreamWriter { + + protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); + + protected final MessagingProcessor messagingProcessor; + protected final StreamObserver streamObserver; + + public ReceiveMessageResponseStreamWriter( + MessagingProcessor messagingProcessor, + StreamObserver observer) { + this.messagingProcessor = messagingProcessor; + this.streamObserver = observer; + } + + public void write(ProxyContext ctx, ReceiveMessageRequest request, PopResult popResult) { + PopStatus status = popResult.getPopStatus(); + List messageFoundList = popResult.getMsgFoundList(); + try { + switch (status) { + case FOUND: + if (messageFoundList.isEmpty()) { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no new message")) + .build()); + } else { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + Iterator messageIterator = messageFoundList.iterator(); + while (messageIterator.hasNext()) { + MessageExt curMessageExt = messageIterator.next(); + Message curMessage = convertToMessage(curMessageExt); + try { + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setMessage(curMessage) + .build()); + } catch (Throwable t) { + this.processThrowableWhenWriteMessage(t, ctx, request, curMessageExt); + messageIterator.forEachRemaining(messageExt -> + this.processThrowableWhenWriteMessage(t, ctx, request, messageExt)); + return; + } + } + } + break; + case POLLING_FULL: + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .build()); + break; + case NO_NEW_MSG: + case POLLING_NOT_FOUND: + default: + streamObserver.onNext(ReceiveMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no new message")) + .build()); + break; + } + } catch (Throwable t) { + write(ctx, request, t); + } finally { + streamObserver.onCompleted(); + } + } + + protected Message convertToMessage(MessageExt messageExt) { + return GrpcConverter.buildMessage(messageExt); + } + + protected void processThrowableWhenWriteMessage(Throwable throwable, + ProxyContext ctx, ReceiveMessageRequest request, MessageExt messageExt) { + + ReceiptHandle handle = ReceiptHandle.create(messageExt); + if (handle == null) { + return; + } + + this.messagingProcessor.changeInvisibleTime( + ctx, + handle, + messageExt.getMsgId(), + GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), + NACK_INVISIBLE_TIME + ); + } + + public void write(ProxyContext ctx, Code code, String message) { + ResponseWriter.write( + streamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(code, message)).build() + ); + } + + public void write(ProxyContext ctx, ReceiveMessageRequest request, Throwable throwable) { + ResponseWriter.write( + streamObserver, + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() + ); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java new file mode 100644 index 0000000000..d6133ded44 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.grpc.v2.producer; + +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.MessagingProcessor; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ForwardMessageToDLQActivity extends AbstractMessingActivity { + + public ForwardMessageToDLQActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request) { + CompletableFuture future = new CompletableFuture<>(); + try { + ProxyContext context = createContext(ctx); + ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); + + return this.messagingProcessor.forwardMessageToDeadLetterQueue( + context, + receiptHandle, + request.getMessageId(), + GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.wrapResourceWithNamespace(request.getTopic()) + ).thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, + RemotingCommand result) { + return ForwardMessageToDeadLetterQueueResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) + .build(); + } +} 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 new file mode 100644 index 0000000000..49edbcaba8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivity.java @@ -0,0 +1,244 @@ +/* + * 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.grpc.v2.producer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Encoding; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageType; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SendReceipt; +import apache.rocketmq.v2.SystemProperties; +import com.beust.jcommander.internal.Lists; +import com.google.common.collect.Maps; +import com.google.common.hash.Hashing; +import com.google.protobuf.Duration; +import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import io.grpc.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.GrpcProxyException; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.QueueSelector; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; + +public class SendMessageActivity extends AbstractMessingActivity { + + public SendMessageActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + ProxyContext context = createContext(ctx); + CompletableFuture future = new CompletableFuture<>(); + + try { + if (request.getMessagesCount() <= 0) { + throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); + } + + List messageList = request.getMessagesList(); + Resource topic = messageList.get(0).getTopic(); + future = this.messagingProcessor.sendMessage( + context, + new SendMessageQueueSelector(request), + GrpcConverter.wrapResourceWithNamespace(topic), + buildMessage(context, request.getMessagesList(), topic) + ).thenApply(result -> convertToSendMessageResponse(context, request, result)); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected List buildMessage(ProxyContext context, List protoMessageList, Resource topic) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + List messageExtList = new ArrayList<>(); + for (apache.rocketmq.v2.Message protoMessage : protoMessageList) { + if (!protoMessage.getTopic().equals(topic)) { + throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); + } + // here use topicName as producerGroup for transactional checker. + messageExtList.add(buildMessage(protoMessage, topicName)); + } + return messageExtList; + } + + protected MessageExt buildMessage(Message protoMessage, String producerGroup) { + String topicName = GrpcConverter.wrapResourceWithNamespace(protoMessage.getTopic()); + + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topicName); + messageExt.setBody(protoMessage.getBody().toByteArray()); + Map messageProperty = this.buildMessageProperty(protoMessage, producerGroup); + + // sysFlag (body encoding & message type) + SystemProperties systemProperties = protoMessage.getSystemProperties(); + int sysFlag = 0; + Encoding bodyEncoding = systemProperties.getBodyEncoding(); + if (bodyEncoding.equals(Encoding.GZIP)) { + sysFlag |= MessageSysFlag.COMPRESSED_FLAG; + } + // transaction + MessageType messageType = systemProperties.getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; + } + messageExt.setSysFlag(sysFlag); + + MessageAccessor.setProperties(messageExt, messageProperty); + return messageExt; + } + + protected Map buildMessageProperty(Message message, String producerGroup) { + org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); + // set user properties + Map userProperties = message.getUserPropertiesMap(); + for (String key : userProperties.keySet()) { + if (MessageConst.STRING_HASH_SET.contains(key)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); + } + } + MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); + + // set tag + String tag = message.getSystemProperties().getTag(); + if (!"".equals(tag)) { + messageWithHeader.setTags(tag); + } + + // set keys + List keysList = message.getSystemProperties().getKeysList(); + if (keysList.size() > 0) { + messageWithHeader.setKeys(keysList); + } + + // set message id + String messageId = message.getSystemProperties().getMessageId(); + if ("".equals(messageId)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); + } + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); + + // set transaction property + MessageType messageType = message.getSystemProperties().getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); + + Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); + + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, + String.valueOf(Durations.toSeconds(transactionResolveDelay))); + } + + // set delay level or deliver timestamp + if (message.getSystemProperties().hasDeliveryTimestamp()) { + Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); + String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); + } + + // set reconsume times + int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); + MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); + // set producer group + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); + // set message group + String messageGroup = message.getSystemProperties().getMessageGroup(); + if (!messageGroup.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); + } + // set trace context + String traceContext = message.getSystemProperties().getTraceContext(); + if (!traceContext.isEmpty()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); + } + return messageWithHeader.getProperties(); + } + + protected SendMessageResponse convertToSendMessageResponse(ProxyContext ctx, SendMessageRequest request, + SendResult result) { + if (result.getSendStatus() != SendStatus.SEND_OK) { + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + } + + List sendReceiptList = Lists.newArrayList(); + sendReceiptList.add(SendReceipt.newBuilder() + .setMessageId(StringUtils.defaultString(result.getMsgId())) + .setTransactionId(StringUtils.defaultString(result.getTransactionId())) + .build()); + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllReceipts(sendReceiptList) + .build(); + } + + protected static class SendMessageQueueSelector implements QueueSelector { + + private final SendMessageRequest request; + + public SendMessageQueueSelector(SendMessageRequest request) { + this.request = request; + } + + @Override + public SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { + try { + Message message = request.getMessages(0); + String shardingKey = null; + if (request.getMessagesCount() == 1) { + shardingKey = message.getSystemProperties().getMessageGroup(); + } + SelectableMessageQueue targetMessageQueue; + if (StringUtils.isNotEmpty(shardingKey)) { + // With shardingKey + List writeQueues = messageQueueView.getWriteSelector().getQueues(); + int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); + targetMessageQueue = writeQueues.get(bucket); + } else { + targetMessageQueue = messageQueueView.getWriteSelector().selectOne(false); + } + return targetMessageQueue; + } catch (Exception e) { + return null; + } + } + } + +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java new file mode 100644 index 0000000000..dd4f2471eb --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -0,0 +1,246 @@ +/* + * 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.grpc.v2.route; + +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Assignment; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.Permission; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; +import com.google.common.net.HostAndPort; +import io.grpc.Context; +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.common.constant.PermName; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.MessagingProcessor; +import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; + +public class RouteActivity extends AbstractMessingActivity { + + public RouteActivity(MessagingProcessor messagingProcessor, + + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + CompletableFuture future = new CompletableFuture<>(); + try { + ProxyContext context = createContext(ctx); + List addressList = this.convertToAddressList(request.getEndpoints()); + + ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( + context, + addressList, + GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + + List messageQueueList = new ArrayList<>(); + Map> brokerMap = buildBrokerMap(proxyTopicRouteData.getBrokerDatas()); + + for (QueueData queueData : proxyTopicRouteData.getQueueDatas()) { + String brokerName = queueData.getBrokerName(); + Map brokerIdMap = brokerMap.get(brokerName); + if (brokerIdMap == null) { + break; + } + for (Broker broker : brokerIdMap.values()) { + messageQueueList.addAll(this.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); + } + } + + QueryRouteResponse response = QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllMessageQueues(messageQueueList) + .build(); + future.complete(response); + } catch (Throwable t) { + if (TopicRouteHelper.isTopicNotExistError(t)) { + future.complete(QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) + .build()); + } else { + future.completeExceptionally(t); + } + } + return future; + } + + public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + CompletableFuture future = new CompletableFuture<>(); + + try { + ProxyContext context = createContext(ctx); + List addressList = this.convertToAddressList(request.getEndpoints()); + + ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( + context, + addressList, + GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + + List assignments = new ArrayList<>(); + Map> brokerMap = buildBrokerMap(proxyTopicRouteData.getBrokerDatas()); + for (QueueData queueData : proxyTopicRouteData.getQueueDatas()) { + Map brokerIdMap = brokerMap.get(queueData.getBrokerName()); + if (brokerIdMap != null) { + for (Map.Entry brokerIdEntry : brokerIdMap.entrySet()) { + MessageQueue defaultMessageQueue = MessageQueue.newBuilder() + .setTopic(request.getTopic()) + .setId(-1) + .setPermission(this.convertToPermission(queueData.getPerm())) + .setBroker(brokerIdEntry.getValue()) + .build(); + + assignments.add(Assignment.newBuilder() + .setMessageQueue(defaultMessageQueue) + .build()); + } + } + } + QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() + .addAllAssignments(assignments) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build(); + future.complete(response); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected Permission convertToPermission(int perm) { + boolean isReadable = PermName.isReadable(perm); + boolean isWriteable = PermName.isWriteable(perm); + if (isReadable && isWriteable) { + return Permission.READ_WRITE; + } + if (isReadable) { + return Permission.READ; + } + if (isWriteable) { + return Permission.WRITE; + } + return Permission.NONE; + } + + protected List convertToAddressList(Endpoints endpoints) { + List addressList = new ArrayList<>(); + for (Address address : endpoints.getAddressesList()) { + addressList.add(new org.apache.rocketmq.proxy.common.Address( + org.apache.rocketmq.proxy.common.Address.AddressScheme.valueOf(endpoints.getScheme().name()), + HostAndPort.fromParts(address.getHost(), address.getPort())) + ); + } + return addressList; + } + + protected Map> buildBrokerMap( + List brokerDataList) { + Map> brokerMap = new HashMap<>(); + for (ProxyTopicRouteData.ProxyBrokerData brokerData : brokerDataList) { + Map brokerIdMap = new HashMap<>(); + String brokerName = brokerData.getBrokerName(); + for (Map.Entry> entry : brokerData.getBrokerAddrs().entrySet()) { + Long brokerId = entry.getKey(); + List
addressList = new ArrayList<>(); + AddressScheme addressScheme = AddressScheme.IPv4; + for (org.apache.rocketmq.proxy.common.Address address : entry.getValue()) { + addressScheme = AddressScheme.valueOf(address.getAddressScheme().name()); + addressList.add(Address.newBuilder() + .setHost(address.getHostAndPort().getHost()) + .setPort(address.getHostAndPort().getPort()) + .build()); + } + + Broker broker = Broker.newBuilder() + .setName(brokerName) + .setId(Math.toIntExact(brokerId)) + .setEndpoints(Endpoints.newBuilder() + .setScheme(addressScheme) + .addAllAddresses(addressList) + .build()) + .build(); + + brokerIdMap.put(brokerId, broker); + } + brokerMap.put(brokerName, brokerIdMap); + } + return brokerMap; + } + + protected List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { + List messageQueueList = new ArrayList<>(); + + int r = 0; + int w = 0; + int rw = 0; + if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { + rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); + r = queueData.getReadQueueNums() - rw; + w = queueData.getWriteQueueNums() - rw; + } else if (PermName.isWriteable(queueData.getPerm())) { + w = queueData.getWriteQueueNums(); + } else if (PermName.isReadable(queueData.getPerm())) { + r = queueData.getReadQueueNums(); + } + + // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. + int queueIdIndex = 0; + for (int i = 0; i < r; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ) + .build(); + messageQueueList.add(messageQueue); + } + + for (int i = 0; i < w; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.WRITE) + .build(); + messageQueueList.add(messageQueue); + } + + for (int i = 0; i < rw; i++) { + MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) + .setId(queueIdIndex++) + .setPermission(Permission.READ_WRITE) + .build(); + messageQueueList.add(messageQueue); + } + + return messageQueueList; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java deleted file mode 100644 index 307d9cea42..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/AbstractRouteService.java +++ /dev/null @@ -1,99 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.proxy.common.ParameterConverter; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.AssignmentQueueSelector; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultAssignmentQueueSelector; - -public abstract class AbstractRouteService extends BaseService { - protected volatile ParameterConverter queryRouteEndpointConverter; - protected volatile ResponseHook queryRouteHook; - - protected volatile ParameterConverter queryAssignmentEndpointConverter; - protected volatile ResponseHook queryAssignmentHook; - protected volatile AssignmentQueueSelector assignmentQueueSelector; - - protected final GrpcClientManager grpcClientManager; - - public AbstractRouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { - super(connectorManager); - this.grpcClientManager = grpcClientManager; - this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; - this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; - this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.connectorManager.getTopicRouteCache()); - } - - public abstract CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); - - public abstract CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - - public ParameterConverter getQueryRouteEndpointConverter() { - return queryRouteEndpointConverter; - } - - public void setQueryRouteEndpointConverter( - ParameterConverter queryRouteEndpointConverter) { - this.queryRouteEndpointConverter = queryRouteEndpointConverter; - } - - public ResponseHook getQueryRouteHook() { - return queryRouteHook; - } - - public void setQueryRouteHook( - ResponseHook queryRouteHook) { - this.queryRouteHook = queryRouteHook; - } - - public ParameterConverter getQueryAssignmentEndpointConverter() { - return queryAssignmentEndpointConverter; - } - - public void setQueryAssignmentEndpointConverter( - ParameterConverter queryAssignmentEndpointConverter) { - this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; - } - - public AssignmentQueueSelector getAssignmentQueueSelector() { - return assignmentQueueSelector; - } - - public void setAssignmentQueueSelector( - AssignmentQueueSelector assignmentQueueSelector) { - this.assignmentQueueSelector = assignmentQueueSelector; - } - - public ResponseHook getQueryAssignmentHook() { - return queryAssignmentHook; - } - - public void setQueryAssignmentHook( - ResponseHook queryAssignmentHook) { - this.queryAssignmentHook = queryAssignmentHook; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 1f1cadb746..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,122 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.util.Iterator; -import java.util.List; -import org.apache.rocketmq.client.consumer.PopStatus; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; - -public abstract class BaseReceiveMessageResponseStreamWriter { - - protected final StreamObserver streamObserver; - protected final ResponseHook receiveMessageHook; - protected final ReceiveMessageResultFilter receiveMessageResultFilter; - - public interface Builder { - BaseReceiveMessageResponseStreamWriter build( - StreamObserver observer, - ResponseHook hook); - } - - public BaseReceiveMessageResponseStreamWriter( - StreamObserver observer, - ResponseHook hook, - ReceiveMessageResultFilter messageResultFilter) { - streamObserver = observer; - receiveMessageHook = hook; - receiveMessageResultFilter = messageResultFilter; - } - - public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - try { - switch (status) { - case FOUND: - List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); - if (messageList.isEmpty()) { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - } else { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - Iterator messageIterator = messageList.iterator(); - while (messageIterator.hasNext()) { - Message curMessage = messageIterator.next(); - try { - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setMessage(curMessage) - .build()); - } catch (Throwable t) { - this.processThrowableWhenWriteMessage(t, ctx, request, curMessage); - messageIterator.forEachRemaining(message -> - this.processThrowableWhenWriteMessage(t, ctx, request, message)); - return; - } - } - } - break; - case POLLING_FULL: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) - .build()); - break; - case NO_NEW_MSG: - case POLLING_NOT_FOUND: - default: - responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) - .build()); - break; - } - } catch (Throwable t) { - write(ctx, request, t); - } finally { - responseStreamObserver.onCompleted(); - } - } - - protected abstract void processThrowableWhenWriteMessage(Throwable throwable, - Context context, ReceiveMessageRequest request, Message message); - - public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { - ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( - ctx, - request, - receiveMessageHook, - streamObserver); - ResponseWriter.write( - responseStreamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() - ); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java deleted file mode 100644 index 350335f1fd..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseReceiveMessageResultFilter.java +++ /dev/null @@ -1,67 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Settings; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.utils.FilterUtils; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; - -public abstract class BaseReceiveMessageResultFilter implements ReceiveMessageResultFilter { - - protected final GrpcClientManager grpcClientManager; - - public BaseReceiveMessageResultFilter(GrpcClientManager manager) { - grpcClientManager = manager; - } - - @Override - public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { - if (messageExtList == null || messageExtList.isEmpty()) { - return Collections.emptyList(); - } - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); - Settings settings = grpcClientManager.getClientSettings(ctx); - int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); - List resMessageList = new ArrayList<>(); - for (MessageExt messageExt : messageExtList) { - if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { - processNoMatchMessage(ctx, request, messageExt); - continue; - } - if (messageExt.getReconsumeTimes() >= maxAttempts) { - processExceedMaxAttemptsMessage(ctx, request, messageExt, maxAttempts); - continue; - } - resMessageList.add(GrpcConverter.buildMessage(messageExt)); - } - return resMessageList; - } - - protected abstract void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt); - - protected abstract void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempts); -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java deleted file mode 100644 index 8d2a923323..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/BaseService.java +++ /dev/null @@ -1,77 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.Resource; -import io.grpc.Context; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; - -public abstract class BaseService implements StartAndShutdown { - - protected final ConnectorManager connectorManager; - - public BaseService(ConnectorManager connectorManager) { - this.connectorManager = connectorManager; - } - - public static ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { - ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); - if (receiptHandle.isExpired()) { - throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); - } - return receiptHandle; - } - - public static String getBrokerAddr(Context ctx, TopicRouteCache topicRouteCache, String brokerName) throws Exception { - if (StringUtils.isBlank(brokerName)) { - throw new ProxyException(Code.UNRECOGNIZED, "broker name is empty"); - } - String addr = topicRouteCache.getBrokerAddr(brokerName); - if (StringUtils.isBlank(addr)) { - throw new ProxyException(Code.UNRECOGNIZED, brokerName + " not exist"); - } - return addr; - } - - protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { - return getBrokerAddr(ctx, this.connectorManager.getTopicRouteCache(), brokerName); - } - - protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { - // for checking filterExpression. - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcConverter.buildSubscriptionData(topicName, filterExpression); - } - - @Override - public void start() throws Exception { - - } - - @Override - public void shutdown() throws Exception { - - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java deleted file mode 100644 index 40897b4ea6..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClientSettingsService.java +++ /dev/null @@ -1,65 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; - -public class ClientSettingsService { - - private final ChannelManager channelManager; - private final GrpcClientManager grpcClientManager; - private final TelemetryCommandManager telemetryCommandManager; - - public ClientSettingsService(ChannelManager channelManager, - GrpcClientManager grpcClientManager, - TelemetryCommandManager telemetryCommandManager) { - this.channelManager = channelManager; - this.grpcClientManager = grpcClientManager; - this.telemetryCommandManager = telemetryCommandManager; - } - - public TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - grpcClientManager.updateClientSettings(clientId, request.getSettings()); - Settings settings = grpcClientManager.getClientSettings(clientId); - if (settings.hasPublishing()) { - for (Resource topic : settings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); - producerChannel.setClientObserver(responseObserver); - } - } - if (settings.hasSubscription()) { - String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); - GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); - consumerChannel.setClientObserver(responseObserver); - } - return TelemetryCommand.newBuilder() - .setSettings(settings) - .build(); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java deleted file mode 100644 index f47dcc9071..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ClusterGrpcService.java +++ /dev/null @@ -1,183 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.rocketmq.common.ThreadFactoryImpl; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; - -public class ClusterGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") - ); - - protected ChannelManager channelManager; - protected ConnectorManager connectorManager; - protected ProducerService producerService; - protected ConsumerService consumerService; - protected RouteService routeService; - protected ForwardClientService clientService; - protected TransactionService transactionService; - protected TelemetryCommandManager pollCommandResponseManager; - protected GrpcClientManager grpcClientManager; - - public ClusterGrpcService() { - this.init(); - } - - protected void init() { - this.channelManager = new ChannelManager(); - this.grpcClientManager = new GrpcClientManager(); - this.pollCommandResponseManager = new TelemetryCommandManager(); - this.connectorManager = new ConnectorManager(new GrpcTransactionStateChecker()); - this.consumerService = new ConsumerService(connectorManager, grpcClientManager); - this.producerService = new ProducerService(connectorManager); - this.routeService = new RouteService(connectorManager, grpcClientManager); - this.clientService = new ForwardClientService(connectorManager, scheduledExecutorService, - channelManager, grpcClientManager, pollCommandResponseManager); - this.transactionService = new TransactionService(connectorManager, channelManager); - - this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); - this.appendStartAndShutdown(this.connectorManager); - this.appendStartAndShutdown(this.consumerService); - this.appendStartAndShutdown(this.producerService); - this.appendStartAndShutdown(this.routeService); - this.appendStartAndShutdown(this.clientService); - this.appendStartAndShutdown(this.transactionService); - } - - @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return routeService.queryRoute(ctx, request); - } - - @Override - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - return clientService.heartbeat(ctx, request); - } - - @Override - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - return producerService.sendMessage(ctx, request); - } - - @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return routeService.queryAssignment(ctx, request); - } - - @Override - public void receiveMessage(Context ctx, ReceiveMessageRequest request, - StreamObserver responseObserver) { - consumerService.receiveMessage(ctx, request, responseObserver); - } - - @Override - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - return consumerService.ackMessage(ctx, request); - } - - @Override - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { - return producerService.forwardMessageToDeadLetterQueue(ctx, request); - } - - @Override - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - return transactionService.endTransaction(ctx, request); - } - - @Override - public CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request) { - return clientService.notifyClientTermination(ctx, request); - } - - @Override - public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { - return consumerService.changeInvisibleDuration(ctx, request); - } - - @Override - public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { - return clientService.telemetry(ctx, responseObserver); - } - - protected class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { - - @Override - public void start() throws Exception { - } - - @Override - public void shutdown() throws Exception { - scheduledExecutorService.shutdown(); - } - } - - protected class GrpcTransactionStateChecker implements TransactionStateChecker { - - @Override - public void checkTransactionState(TransactionStateCheckRequest checkData) { - transactionService.checkTransactionState(checkData); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java deleted file mode 100644 index dbcf3bd638..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcService.java +++ /dev/null @@ -1,565 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.AckMessageEntry; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.AckMessageResultEntry; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.TelemetryCommand; -import apache.rocketmq.v2.ThreadStackTrace; -import apache.rocketmq.v2.VerifyMessageResult; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import io.netty.channel.Channel; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.broker.client.ClientChannelInfo; -import org.apache.rocketmq.broker.client.ConsumerGroupEvent; -import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; -import org.apache.rocketmq.broker.client.ProducerChangeListener; -import org.apache.rocketmq.broker.client.ProducerGroupEvent; -import org.apache.rocketmq.client.consumer.PopStatus; -import org.apache.rocketmq.common.MQVersion; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageBatch; -import org.apache.rocketmq.common.message.MessageClientIDSetter; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; -import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResponseStreamWriter; -import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResultFilter; -import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; -import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; -import org.apache.rocketmq.remoting.RemotingServer; -import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; -import org.apache.rocketmq.remoting.protocol.LanguageCode; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class LocalGrpcService extends AbstractStartAndShutdown implements GrpcForwardService { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - private final BrokerController brokerController; - private final ChannelManager channelManager; - private final TelemetryCommandManager telemetryCommandManager; - private final GrpcClientManager grpcClientManager; - private final RouteService routeService; - private final ClientSettingsService clientSettingsService; - private final LocalWriteQueueSelector localWriteQueueSelector; - private final BaseReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; - - private volatile ResponseHook receiveMessageHook; - - public LocalGrpcService(BrokerController brokerController) { - this(brokerController, new TelemetryCommandManager()); - } - - /** - * For unit test - * @param brokerController BrokerController works in local mode - * @param telemetryCommandManager Used to manage telemetry command - */ - LocalGrpcService(BrokerController brokerController, TelemetryCommandManager telemetryCommandManager) { - this.brokerController = brokerController; - this.channelManager = new ChannelManager(); - // TransactionStateChecker is not used in Local mode. - ConnectorManager connectorManager = new ConnectorManager(null); - this.telemetryCommandManager = telemetryCommandManager; - this.grpcClientManager = new GrpcClientManager(); - this.routeService = new RouteService(connectorManager, grpcClientManager); - this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); - this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), - brokerController.getTopicConfigManager(), connectorManager.getTopicRouteCache()); - - this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); - this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); - - this.streamWriterBuilder = (observer, hook) -> new LocalReceiveMessageResponseStreamWriter( - observer, - hook, - channelManager, - brokerController, - new LocalReceiveMessageResultFilter(channelManager, brokerController, grpcClientManager) - ); - - this.appendStartAndShutdown(connectorManager); - } - - @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - return this.routeService.queryRoute(ctx, request); - } - - @Override - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - LanguageCode languageCode; - String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - languageCode = LanguageCode.valueOf(language); - - Settings clientSettings = grpcClientManager.getClientSettings(clientId); - HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); - command.setLanguage(languageCode); - command.setVersion(MQVersion.Version.V5_0_0.ordinal()); - command.setBody(heartbeatData.encode()); - command.makeCustomHeaderToNet(); - - CompletableFuture future = new CompletableFuture<>(); - switch (clientSettings.getClientType()) { - case PRODUCER: { - for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - - this.brokerController.getClientManageProcessor() - .heartBeat(simpleChannelHandlerContext, command); - } - HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "Producer heartbeat")) - .build(); - future.complete(heartbeatResponse); - break; - } - case PUSH_CONSUMER: - case SIMPLE_CONSUMER: { - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - - RemotingCommand response = this.brokerController.getClientManageProcessor() - .heartBeat(simpleChannelHandlerContext, command); - HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) - .build(); - future.complete(heartbeatResponse); - break; - } - default: { - throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); - } - } - - return future; - } - - @Override - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - MessageQueue messageQueue = localWriteQueueSelector.selectQueue(ctx, request).getMessageQueue(); - String topicName = messageQueue.getTopic(); - SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName, messageQueue.getQueueId()); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); - List messageList = GrpcConverter.buildMessage(request.getMessagesList(), request.getMessages(0).getTopic()); - String messageId; - if (messageList.size() == 1) { - org.apache.rocketmq.common.message.Message message = messageList.get(0); - command.setBody(message.getBody()); - messageId = MessageClientIDSetter.getUniqID(message); - } else { - MessageBatch messageBatch = MessageBatch.generateFromList(messageList); - MessageClientIDSetter.setUniqID(messageBatch); - messageBatch.setBody(messageBatch.encode()); - command.setBody(messageBatch.encode()); - messageId = MessageClientIDSetter.getUniqID(messageBatch); - } - command.makeCustomHeaderToNet(); - - SendMessageResponseHandler handler = new SendMessageResponseHandler(messageId, requestHeader.getSysFlag(), brokerController.getBrokerAddr()); - SendMessageChannel channel = channelManager.createChannel(ctx, context -> new SendMessageChannel(context, handler), SendMessageChannel.class); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture future = new CompletableFuture<>(); - InvocationContext context - = new InvocationContext<>(request, future); - channel.registerInvocationContext(command.getOpaque(), context); - try { - RemotingCommand response = brokerController.getSendMessageProcessor() - .processRequest(channelHandlerContext, command); - if (response != null) { - handler.handle(response, context); - channel.eraseInvocationContext(command.getOpaque()); - } - } catch (final Exception e) { - log.error("Failed to process send message command", e); - channel.eraseInvocationContext(command.getOpaque()); - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - return this.routeService.queryAssignment(ctx, request); - } - - @Override - public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); - // TODO: get fifo config from subscriptionGroupManager - boolean fifo = false; - BaseReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); - ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); - ReceiveMessageChannel channel = channelManager.createChannel(ctx, context -> new ReceiveMessageChannel(context, handler), ReceiveMessageChannel.class); - CompletableFuture> future = new CompletableFuture<>(); - InvocationContext> context - = new InvocationContext<>(request, future); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); - command.makeCustomHeaderToNet(); - channel.registerInvocationContext(command.getOpaque(), context); - try { - RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(channelHandlerContext, command); - if (response != null) { - handler.handle(response, context); - channel.eraseInvocationContext(command.getOpaque()); - } - } catch (Exception e) { - log.error("Failed to process pop message command", e); - channel.eraseInvocationContext(command.getOpaque()); - future.completeExceptionally(e); - } - future.thenAccept(r -> writer.write(ctx, request, PopStatus.FOUND, r)) - .exceptionally(e -> { - writer.write(ctx, request, e); - return null; - }); - } - - @Override - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - CompletableFuture future = new CompletableFuture<>(); - List ackMessageResultEntryList = new ArrayList<>(); - for (AckMessageEntry entry : request.getEntriesList()) { - ReceiptHandle receiptHandle = ReceiptHandle.decode(entry.getReceiptHandle()); - if (receiptHandle.isExpired()) { - ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() - .setReceiptHandle(entry.getReceiptHandle()) - .setMessageId(entry.getMessageId()) - .setStatus(ResponseBuilder.buildStatus(Code.RECEIPT_HANDLE_EXPIRED, "expired")) - .build()); - continue; - } - AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, receiptHandle); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); - command.makeCustomHeaderToNet(); - - try { - RemotingCommand responseCommand = brokerController.getAckMessageProcessor() - .processRequest(channelHandlerContext, command); - ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() - .setReceiptHandle(entry.getReceiptHandle()) - .setMessageId(entry.getMessageId()) - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .build()); - } catch (Exception e) { - log.error("Exception raised when ack message", e); - ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() - .setReceiptHandle(entry.getReceiptHandle()) - .setMessageId(entry.getMessageId()) - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, e.getMessage())) - .build()); - } - } - AckMessageResponse response = AckMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, "ok")) - .addAllEntries(ackMessageResultEntryList) - .build(); - future.complete(response); - return future; - } - - @Override - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { - SimpleChannel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - - ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); - command.makeCustomHeaderToNet(); - - CompletableFuture future = new CompletableFuture<>(); - try { - RemotingCommand response = brokerController.getSendMessageProcessor() - .processRequest(channelHandlerContext, command); - - future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) - .build()); - } catch (Exception e) { - log.error("Exception raised when forwardMessageToDeadLetterQueue", e); - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request, topicName); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); - command.makeCustomHeaderToNet(); - - CompletableFuture future = new CompletableFuture<>(); - try { - RemotingCommand responseCommand = brokerController.getEndTransactionProcessor() - .processRequest(channelHandlerContext, command); - EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); - if (null != responseCommand) { - builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); - } else { - builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); - } - EndTransactionResponse response = builder.build(); - future.complete(response); - } catch (Exception e) { - log.error("Exception raised while endTransaction", e); - future.completeExceptionally(e); - } - return future; - } - - public void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { - String nonce = request.getNonce(); - String threadStack = request.getThreadStackTrace(); - TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); - if (pollCommandResponseFuture != null) { - Integer opaque = pollCommandResponseFuture.getOpaque(); - if (opaque != null) { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); - remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(threadStack); - remotingCommand.setBody(runningInfo.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); - } - } - } - } - - public void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { - String nonce = request.getNonce(); - TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); - if (pollCommandResponseFuture != null) { - Integer opaque = pollCommandResponseFuture.getOpaque(); - if (opaque != null) { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); - remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); - ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); - remotingCommand.setBody(result.encode()); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); - } - } - } - } - - @Override - public CompletableFuture notifyClientTermination(Context ctx, - NotifyClientTerminationRequest request) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - Settings clientSettings = grpcClientManager.getClientSettings(clientId); - UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); - - RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); - remotingCommand.makeCustomHeaderToNet(); - try { - this.brokerController.getClientManageProcessor().unregisterClient(simpleChannelHandlerContext, remotingCommand); - } catch (Exception ignored) { - } - return new CompletableFuture<>(); - } - - @Override - public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); - - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); - ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); - command.makeCustomHeaderToNet(); - - CompletableFuture future = new CompletableFuture<>(); - try { - RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() - .processRequest(channelHandlerContext, command); - ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); - ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); - if (responseCommand.getCode() == ResponseCode.SUCCESS) { - builder.setReceiptHandle(ReceiptHandle.builder() - .startOffset(requestHeader.getOffset()) - .retrieveTime(responseHeader.getPopTime()) - .invisibleTime(responseHeader.getInvisibleTime()) - .reviveQueueId(responseHeader.getReviveQid()) - .topicType(receiptHandle.getTopicType()) - .brokerName(brokerController.getBrokerConfig().getBrokerName()) - .queueId(requestHeader.getQueueId()) - .offset(requestHeader.getOffset()) - .build() - .encode()); - } - - future.complete(builder.build()); - } catch (Exception e) { - log.error("Exception raised while changeInvisibleDuration", e); - future.completeExceptionally(e); - } - return future; - } - - @Override - public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - return new StreamObserver() { - @Override - public void onNext(TelemetryCommand request) { - switch (request.getCommandCase()) { - case SETTINGS: { - responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); - break; - } - case THREAD_STACK_TRACE: { - reportThreadStackTrace(ctx, request.getThreadStackTrace()); - break; - } - case VERIFY_MESSAGE_RESULT: { - reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); - break; - } - default: { - throw new IllegalArgumentException("Request type is illegal"); - } - } - } - - @Override - public void onError(Throwable t) { - - } - - @Override - public void onCompleted() { - responseObserver.onCompleted(); - } - }; - } - - protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { - - @Override - public void handle(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]; - channelManager.onClientOffline(clientChannelInfo.getClientId()); - grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); - } - } - } - - @Override - public void shutdown() { - - } - } - - protected class ProducerChangeListenerImpl implements ProducerChangeListener { - - @Override - public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { - if (event == ProducerGroupEvent.CLIENT_UNREGISTER) { - channelManager.onClientOffline(clientChannelInfo.getClientId()); - grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); - } - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java deleted file mode 100644 index 16a2f29d43..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResponseStreamObserver.java +++ /dev/null @@ -1,67 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; - -public class ReceiveMessageResponseStreamObserver implements StreamObserver { - - private final Context context; - private final ReceiveMessageRequest request; - private final ResponseHook receiveMessageHook; - private final StreamObserver observer; - - public ReceiveMessageResponseStreamObserver(Context context, ReceiveMessageRequest request, - ResponseHook receiveMessageHook, - StreamObserver observer) { - this.context = context; - this.request = request; - this.receiveMessageHook = receiveMessageHook; - this.observer = observer; - } - - @Override - public void onNext(ReceiveMessageResponse response) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, response, null); - } - observer.onNext(response); - } - - @Override - public void onError(Throwable throwable) { - if (receiveMessageHook != null) { - receiveMessageHook.beforeResponse(context, request, null, throwable); - } - observer.onError(throwable); - } - - @Override - public void onCompleted() { - observer.onCompleted(); - } - - public boolean isCancelled() { - return ResponseWriter.isCancelled(observer); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java deleted file mode 100644 index 474ed29f15..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerService.java +++ /dev/null @@ -1,283 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.AckMessageEntry; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.AckMessageResultEntry; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; - -public class ConsumerService extends BaseService { - protected final ForwardReadConsumer readConsumer; - protected final ForwardWriteConsumer writeConsumer; - /** - * For sending messages back to broker. - */ - protected final ForwardProducer producer; - protected final GrpcClientManager grpcClientManager; - - private volatile ReadQueueSelector readQueueSelector; - private volatile BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; - - private volatile ResponseHook receiveMessageHook; - private volatile ResponseHook ackMessageHook; - private volatile ResponseHook changeInvisibleDurationHook; - - public ConsumerService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { - super(connectorManager); - this.readConsumer = connectorManager.getForwardReadConsumer(); - this.writeConsumer = connectorManager.getForwardWriteConsumer(); - this.producer = connectorManager.getForwardProducer(); - this.grpcClientManager = grpcClientManager; - - this.readQueueSelector = new DefaultReadQueueSelector(connectorManager.getTopicRouteCache()); - this.receiveMessageWriterBuilder = (observer, hook) -> new DefaultReceiveMessageResponseStreamWriter( - observer, - hook, - writeConsumer, - connectorManager.getTopicRouteCache(), - new DefaultReceiveMessageResultFilter( - producer, writeConsumer, grpcClientManager, connectorManager.getTopicRouteCache()) - ); - } - - public void receiveMessage(Context ctx, ReceiveMessageRequest request, - StreamObserver responseObserver) { - BaseReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); - try { - PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); - SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); - - if (messageQueue == null) { - throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); - } - - this.readConsumer.popMessage( - ctx, - messageQueue.getBrokerAddr(), - messageQueue.getBrokerName(), - requestHeader, - requestHeader.getPollTime()) - .thenAccept(result -> writer.write(ctx, request, result.getPopStatus(), result.getMsgFoundList())) - .exceptionally(e -> { - writer.write(ctx, request, e); - return null; - }); - } catch (Throwable t) { - writer.write(ctx, request, t); - } - } - - protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { - checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); - boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); - return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); - } - - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (ackMessageHook != null) { - ackMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; - for (int i = 0; i < request.getEntriesCount(); i++) { - futures[i] = processAckMessage(ctx, request, request.getEntries(i)); - } - CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { - if (throwable != null) { - future.completeExceptionally(throwable); - return; - } - List entryList = new ArrayList<>(); - for (CompletableFuture entryFuture : futures) { - entryFuture.thenAccept(entryList::add); - } - AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllEntries(entryList); - future.complete(responseBuilder.build()); - }); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, - AckMessageEntry ackMessageEntry) { - CompletableFuture future = new CompletableFuture<>(); - AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) - .setMessageId(ackMessageEntry.getMessageId()) - .setReceiptHandle(ackMessageEntry.getReceiptHandle()); - - try { - ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); - String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - - AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); - CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageEntry.getMessageId(), requestHeader); - ackResultFuture - .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) - .exceptionally(throwable -> { - future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); - return null; - }); - } catch (Throwable t) { - future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); - } - return future; - } - - protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, - ReceiptHandle handle) { - return GrpcConverter.buildAckMessageRequestHeader(request, handle); - } - - protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, - AckResult ackResult) { - if (AckStatus.OK.equals(ackResult.getStatus())) { - return AckMessageResultEntry.newBuilder() - .setMessageId(ackMessageEntry.getMessageId()) - .setReceiptHandle(ackMessageEntry.getReceiptHandle()) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); - } - return AckMessageResultEntry.newBuilder() - .setMessageId(ackMessageEntry.getMessageId()) - .setReceiptHandle(ackMessageEntry.getReceiptHandle()) - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) - .build(); - } - - public CompletableFuture changeInvisibleDuration(Context ctx, - ChangeInvisibleDurationRequest request) { - CompletableFuture future = new CompletableFuture<>(); - - try { - ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); - String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - - ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); - future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), - request.getMessageId(), requestHeader) - .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); - } catch (Throwable t) { - future.completeExceptionally(t); - } - future.whenComplete((response, throwable) -> { - if (changeInvisibleDurationHook != null) { - changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); - } - }); - return future; - } - - protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, - ChangeInvisibleDurationRequest request) { - return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); - } - - protected ChangeInvisibleDurationResponse convertToChangeInvisibleDurationResponse(Context ctx, - ChangeInvisibleDurationRequest request, AckResult ackResult) { - if (AckStatus.OK.equals(ackResult.getStatus())) { - return ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .setReceiptHandle(ackResult.getExtraInfo()) - .build(); - } - return ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) - .build(); - } - - public ReadQueueSelector getReadQueueSelector() { - return readQueueSelector; - } - - public void setReadQueueSelector(ReadQueueSelector readQueueSelector) { - this.readQueueSelector = readQueueSelector; - } - - public BaseReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { - return receiveMessageWriterBuilder; - } - - public void setReceiveMessageWriterBuilder( - BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { - this.receiveMessageWriterBuilder = receiveMessageWriterBuilder; - } - - public ResponseHook getReceiveMessageHook() { - return receiveMessageHook; - } - - public void setReceiveMessageHook( - ResponseHook receiveMessageHook) { - this.receiveMessageHook = receiveMessageHook; - } - - public ResponseHook getAckMessageHook() { - return ackMessageHook; - } - - public void setAckMessageHook( - ResponseHook ackMessageHook) { - this.ackMessageHook = ackMessageHook; - } - - public ResponseHook getChangeInvisibleDurationHook() { - return changeInvisibleDurationHook; - } - - public void setChangeInvisibleDurationHook( - ResponseHook changeInvisibleDurationHook) { - this.changeInvisibleDurationHook = changeInvisibleDurationHook; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java deleted file mode 100644 index a27ed2a74f..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java +++ /dev/null @@ -1,41 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.QueryAssignmentRequest; -import io.grpc.Context; -import java.util.List; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; - -public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { - - private final TopicRouteCache topicRouteCache; - - public DefaultAssignmentQueueSelector(TopicRouteCache topicRouteCache) { - this.topicRouteCache = topicRouteCache; - } - - @Override - public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topicName); - return messageQueueWrapper.getReadSelector().getBrokerActingQueues(); - } -} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java deleted file mode 100644 index 97b878b871..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelector.java +++ /dev/null @@ -1,55 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; - -public class DefaultReadQueueSelector implements ReadQueueSelector { - - private final TopicRouteCache topicRouteCache; - - public DefaultReadQueueSelector(TopicRouteCache topicRouteCache) { - this.topicRouteCache = topicRouteCache; - } - - @Override - public SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader) { - SelectableMessageQueue messageQueue = null; - try { - String topic = requestHeader.getTopic(); - - if (request.hasMessageQueue() && request.getMessageQueue().hasBroker()) { - String brokerName = request.getMessageQueue().getBroker().getName(); - if (StringUtils.isNotBlank(brokerName)) { - messageQueue = topicRouteCache.selectReadBrokerByName(topic, brokerName); - } - } - - if (messageQueue == null) { - messageQueue = topicRouteCache.selectOneReadBroker(topic, null); - } - return messageQueue; - } catch (Throwable t) { - return null; - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 10dfda6fcc..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,96 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.time.Duration; -import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; - -public class DefaultReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { - protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); - protected final ForwardWriteConsumer writeConsumer; - protected final TopicRouteCache topicRouteCache; - - public DefaultReceiveMessageResponseStreamWriter( - StreamObserver observer, - ResponseHook hook, - ForwardWriteConsumer writeConsumer, - TopicRouteCache topicRouteCache, - ReceiveMessageResultFilter receiveMessageResultFilter) { - super(observer, hook, receiveMessageResultFilter); - this.writeConsumer = writeConsumer; - this.topicRouteCache = topicRouteCache; - } - - @Override - protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, - Message message) { - this.nackFailToWriteMessage(context, request, message); - } - - protected void nackFailToWriteMessage(Context ctx, ReceiveMessageRequest request, Message message) { - try { - String receiptHandleStr = message.getSystemProperties().getReceiptHandle(); - ReceiptHandle handle = BaseService.resolveReceiptHandle(ctx, receiptHandleStr); - String brokerAddr = BaseService.getBrokerAddr(ctx, this.topicRouteCache, handle.getBrokerName()); - - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); - changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); - changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); - changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); - changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); - changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); - changeInvisibleTimeRequestHeader.setInvisibleTime(NACK_INVISIBLE_TIME); - - this.writeConsumer.changeInvisibleTimeAsync( - ctx, - brokerAddr, - handle.getBrokerName(), - message.getSystemProperties().getMessageId(), - changeInvisibleTimeRequestHeader - ).whenComplete((ackResult, t) -> { - if (t != null) { - log.warn("err when nack message. request:{}, message:{}", request, message, t); - } else if (!AckStatus.OK.equals(ackResult.getStatus())) { - log.warn("nack failed. request:{}, message:{}, ackResult:{}", request, message, ackResult); - } - }); - } catch (Throwable t) { - log.warn("err when nack message. request:{}, message:{}", request, message, t); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java deleted file mode 100644 index adf662e87b..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ /dev/null @@ -1,127 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; - -public class DefaultReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { - - protected final ForwardProducer producer; - protected final ForwardWriteConsumer writeConsumer; - protected final TopicRouteCache topicRouteCache; - - private volatile ResponseHook ackNoMatchedMessageHook; - private volatile ResponseHook forwardToDLQInRecvMessageHook; - - public DefaultReceiveMessageResultFilter(ForwardProducer producer, ForwardWriteConsumer writeConsumer, - GrpcClientManager grpcClientManager, TopicRouteCache topicRouteCache) { - super(grpcClientManager); - this.producer = producer; - this.writeConsumer = writeConsumer; - this.topicRouteCache = topicRouteCache; - } - - @Override - protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { - CompletableFuture future = new CompletableFuture<>(); - - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); - try { - String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - future = this.writeConsumer.ackMessage(ctx, brokerAddr, messageExt.getMsgId(), ackMessageRequestHeader); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((ackResult, throwable) -> { - if (ackNoMatchedMessageHook != null) { - ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); - } - }); - } - - @Override - protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, - int maxAttempts) { - CompletableFuture future = new CompletableFuture<>(); - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); - - try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - String brokerAddr = getBrokerAddr(ctx, topicRouteCache, handle.getBrokerName()); - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( - request, - handle, - messageExt.getMsgId(), - maxAttempts); - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); - - future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((result, throwable) -> { - if (forwardToDLQInRecvMessageHook != null) { - forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); - } - }); - } - - public ResponseHook getAckNoMatchedMessageHook() { - return ackNoMatchedMessageHook; - } - - public void setAckNoMatchedMessageHook( - ResponseHook ackNoMatchedMessageHook) { - this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; - } - - public ResponseHook getForwardToDLQInRecvMessageHook() { - return forwardToDLQInRecvMessageHook; - } - - public void setForwardToDLQInRecvMessageHook( - ResponseHook forwardToDLQInRecvMessageHook) { - this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java deleted file mode 100644 index 0e11112912..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelector.java +++ /dev/null @@ -1,77 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.SendMessageRequest; -import io.grpc.Context; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; - -public class DefaultWriteQueueSelector implements WriteQueueSelector { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected final TopicRouteCache topicRouteCache; - - public DefaultWriteQueueSelector(TopicRouteCache topicRouteCache) { - this.topicRouteCache = topicRouteCache; - } - - @Override - public SelectableMessageQueue selectQueue( - Context ctx, - SendMessageRequest request - ) { - try { - if (request.getMessagesCount() <= 0) { - throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); - } - Message message = request.getMessages(0); - String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); - String shardingKey = null; - if (request.getMessagesCount() == 1) { - shardingKey = message.getSystemProperties().getMessageGroup(); - } - SelectableMessageQueue targetMessageQueue; - if (StringUtils.isNotEmpty(shardingKey)) { - // With shardingKey - targetMessageQueue = selectOrderQueue(topic, shardingKey); - } else { - targetMessageQueue = selectNormalQueue(topic); - } - return targetMessageQueue; - } catch (Exception e) { - log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); - return null; - } - } - - protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { - return this.topicRouteCache.selectOneWriteQueue(topic, null); - } - - protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { - return this.topicRouteCache.selectOneWriteQueueByKey(topic, shardingKey); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java deleted file mode 100644 index d3898bee4d..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientService.java +++ /dev/null @@ -1,266 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.NotifyClientTerminationResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.broker.client.ClientChannelInfo; -import org.apache.rocketmq.broker.client.ConsumerGroupEvent; -import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; -import org.apache.rocketmq.broker.client.ConsumerManager; -import org.apache.rocketmq.broker.client.ProducerChangeListener; -import org.apache.rocketmq.broker.client.ProducerGroupEvent; -import org.apache.rocketmq.broker.client.ProducerManager; -import org.apache.rocketmq.common.MQVersion; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; -import org.apache.rocketmq.remoting.protocol.LanguageCode; - -public class ForwardClientService extends BaseService { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected final ChannelManager channelManager; - protected final GrpcClientManager grpcClientManager; - protected final TelemetryCommandManager telemetryCommandManager; - - protected ConsumerManager consumerManager; - protected ProducerManager producerManager; - protected ClientSettingsService clientSettingsService; - - public ForwardClientService( - ConnectorManager connectorManager, - ScheduledExecutorService scheduledExecutorService, - ChannelManager channelManager, - GrpcClientManager grpcClientManager, - TelemetryCommandManager telemetryCommandManager - ) { - super(connectorManager); - scheduledExecutorService.scheduleWithFixedDelay( - this::scanNotActiveChannel, - Duration.ofSeconds(10).toMillis(), - Duration.ofSeconds(10).toMillis(), - TimeUnit.MILLISECONDS); - this.channelManager = channelManager; - this.grpcClientManager = grpcClientManager; - this.telemetryCommandManager = telemetryCommandManager; - - this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); - this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); - this.producerManager = new ProducerManager(); - this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); - } - - protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { - - @Override - public void handle(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]; - channelManager.onClientOffline(clientChannelInfo.getClientId()); - grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); - } - } - } - - @Override - public void shutdown() { - - } - } - - protected class ProducerChangeListenerImpl implements ProducerChangeListener { - - @Override - public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { - switch (event) { - case GROUP_UNREGISTER: - connectorManager.getTransactionHeartbeatRegisterService().onProducerGroupOffline(group); - break; - case CLIENT_UNREGISTER: - channelManager.onClientOffline(clientChannelInfo.getClientId()); - grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); - break; - default: - break; - } - } - } - - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { - CompletableFuture future = new CompletableFuture<>(); - - try { - String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - LanguageCode languageCode = LanguageCode.valueOf(language); - - Settings clientSettings = grpcClientManager.getClientSettings(clientId); - switch (clientSettings.getClientType()) { - case PRODUCER: { - for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - // use topic name as producer group - producerManager.registerProducer(topicName, clientChannelInfo); - connectorManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); - } - break; - } - case PUSH_CONSUMER: - case SIMPLE_CONSUMER: { - if (!request.hasGroup()) { - throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); - } - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, telemetryCommandManager); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - - consumerManager.registerConsumer( - consumerGroup, - clientChannelInfo, - GrpcConverter.buildConsumeType(clientSettings.getClientType()), - MessageModel.CLUSTERING, - ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, - GrpcConverter.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()), - false - ); - break; - } - default: { - throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); - } - } - future.complete(HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - return future; - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { - CompletableFuture future = new CompletableFuture<>(); - - try { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - Settings clientSettings = grpcClientManager.getClientSettings(clientId); - - switch (clientSettings.getClientType()) { - case PRODUCER: - for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - // user topic name as producer group - GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); - if (channel != null) { - producerManager.doChannelCloseEvent(topicName, channel); - } - } - break; - case PUSH_CONSUMER: - case SIMPLE_CONSUMER: - if (!request.hasGroup()) { - throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); - } - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); - if (channel != null) { - consumerManager.doChannelCloseEvent(consumerGroup, channel); - } - break; - default: - break; - } - future.complete(NotifyClientTerminationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { - return new StreamObserver() { - @Override - public void onNext(TelemetryCommand request) { - if (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) { - responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); - } - } - - @Override - public void onError(Throwable t) { - - } - - @Override - public void onCompleted() { - responseObserver.onCompleted(); - } - }; - } - - private void scanNotActiveChannel() { - try { - this.consumerManager.scanNotActiveChannel(); - this.producerManager.scanNotActiveChannel(); - } catch (Exception e) { - log.error("error occurred when scan not active client channels.", e); - } - } - - public ConsumerManager getConsumerManager() { - return consumerManager; - } - - public ProducerManager getProducerManager() { - return producerManager; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java deleted file mode 100644 index 9fd4ea8e44..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerService.java +++ /dev/null @@ -1,184 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.SendReceipt; -import com.beust.jcommander.internal.Lists; -import io.grpc.Context; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class ProducerService extends BaseService { - - protected final ForwardProducer producer; - private volatile WriteQueueSelector writeQueueSelector; - private volatile ResponseHook sendMessageHook; - private volatile ResponseHook forwardMessageToDLQHook; - - public ProducerService(ConnectorManager connectorManager) { - super(connectorManager); - this.producer = connectorManager.getForwardProducer(); - - this.writeQueueSelector = new DefaultWriteQueueSelector(this.connectorManager.getTopicRouteCache()); - } - - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - CompletableFuture future = new CompletableFuture<>(); - - try { - SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request); - if (selectableMessageQueue == null) { - throw new ProxyException(Code.FORBIDDEN, "no writeable topic route"); - } - - // send message to broker. - future = this.producer.sendMessage( - ctx, - selectableMessageQueue.getBrokerAddr(), - selectableMessageQueue.getBrokerName(), - convertToMessageList(ctx, request), - convertToSendMessageRequestHeader(ctx, request, selectableMessageQueue) - ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); - } catch (Throwable t) { - future.completeExceptionally(t); - } - - future.whenComplete((response, throwable) -> { - if (sendMessageHook != null) { - sendMessageHook.beforeResponse(ctx, request, response, throwable); - } - }); - return future; - } - - protected SendMessageRequestHeader convertToSendMessageRequestHeader(Context ctx, SendMessageRequest request, SelectableMessageQueue selectableMessageQueue) { - // use topic name as group - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessages(0).getTopic()); - return GrpcConverter.buildSendMessageRequestHeader(request, topicName, - selectableMessageQueue.getQueueId()); - } - - protected List convertToMessageList(Context ctx, SendMessageRequest request) { - // use topic name as group - Resource topic = request.getMessages(0).getTopic(); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - return GrpcConverter.buildMessage(request.getMessagesList(), topic); - } - - protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, - SendResult result) { - if (result.getSendStatus() != SendStatus.SEND_OK) { - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); - } - - List sendReceiptList = Lists.newArrayList(); - sendReceiptList.add(SendReceipt.newBuilder() - .setMessageId(StringUtils.defaultString(result.getMsgId())) - .setTransactionId(StringUtils.defaultString(result.getTransactionId())) - .build()); - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllReceipts(sendReceiptList) - .build(); - } - - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { - CompletableFuture future = new CompletableFuture<>(); - - try { - ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); - String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); - ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( - request.getTopic(), request.getGroup(), receiptHandle); - - future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) - .thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); - } catch (Throwable t) { - future.completeExceptionally(t); - } - future.whenComplete((response, throwable) -> { - if (forwardMessageToDLQHook != null) { - forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); - } - }); - return future; - } - - protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, - ForwardMessageToDeadLetterQueueRequest request) { - return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); - } - - protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, - RemotingCommand result) { - return ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) - .build(); - } - - public WriteQueueSelector getWriteQueueSelector() { - return writeQueueSelector; - } - - public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { - this.writeQueueSelector = writeQueueSelector; - } - - public ResponseHook getSendMessageHook() { - return sendMessageHook; - } - - public void setSendMessageHook( - ResponseHook sendMessageHook) { - this.sendMessageHook = sendMessageHook; - } - - public ResponseHook getForwardMessageToDLQHook() { - return forwardMessageToDLQHook; - } - - public void setForwardMessageToDLQHook( - ResponseHook forwardMessageToDLQHook) { - this.forwardMessageToDLQHook = forwardMessageToDLQHook; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java deleted file mode 100644 index b238335f2b..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteService.java +++ /dev/null @@ -1,150 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Assignment; -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.Permission; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; - -public class RouteService extends AbstractRouteService { - public RouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { - super(connectorManager, grpcClientManager); - } - - @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (queryRouteHook != null) { - queryRouteHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); - TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); - List queueDataList = topicRouteData.getQueueDatas(); - - List messageQueueList = new ArrayList<>(); - Endpoints endpoints = request.getEndpoints(); - Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, endpoints); - if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { - future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - endpoints + " is invalidate")) - .build()); - return future; - } - for (QueueData queueData : queueDataList) { - Broker broker = Broker.newBuilder() - .setName(queueData.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); - - messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); - } - QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllMessageQueues(messageQueueList) - .build(); - future.complete(response); - } catch (Throwable t) { - if (TopicRouteHelper.isTopicNotExistError(t)) { - future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) - .build()); - } else { - future.completeExceptionally(t); - } - } - return future; - } - - @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (queryAssignmentHook != null) { - queryAssignmentHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - List assignments = new ArrayList<>(); - List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); - Endpoints endpoints = request.getEndpoints(); - Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, endpoints); - if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { - future.complete(QueryAssignmentResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + - endpoints + " is invalidate")) - .build()); - return future; - } - for (SelectableMessageQueue messageQueue : messageQueueList) { - Broker broker = Broker.newBuilder() - .setName(messageQueue.getBrokerName()) - .setId(0) - .setEndpoints(resEndpoints) - .build(); - - MessageQueue defaultMessageQueue = MessageQueue.newBuilder() - .setTopic(request.getTopic()) - .setId(-1) - .setPermission(Permission.READ_WRITE) - .setBroker(broker) - .build(); - - assignments.add(Assignment.newBuilder() - .setMessageQueue(defaultMessageQueue) - .build()); - } - - QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() - .addAllAssignments(assignments) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); - future.complete(response); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java deleted file mode 100644 index 9600d7acc2..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionService.java +++ /dev/null @@ -1,139 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ThreadLocalRandom; -import org.apache.commons.collections.CollectionUtils; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -import org.apache.rocketmq.remoting.common.RemotingHelper; - -public class TransactionService extends BaseService implements TransactionStateChecker { - - protected final ChannelManager channelManager; - protected final ForwardProducer forwardProducer; - - private volatile ResponseHook checkTransactionStateHook; - private volatile ResponseHook endTransactionHook; - - public TransactionService(ConnectorManager connectorManager, ChannelManager channelManager) { - super(connectorManager); - this.forwardProducer = connectorManager.getForwardProducer(); - this.channelManager = channelManager; - } - - @Override - public void checkTransactionState(TransactionStateCheckRequest checkData) { - Context ctx = Context.current(); - try { - List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); - if (CollectionUtils.isEmpty(clientIdList)) { - return; - } - - String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); - GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); - - String transactionId = checkData.getTransactionId().getProxyTransactionId(); - MessageExt messageExt = checkData.getMessageExt(); - Message message = GrpcConverter.buildMessage(messageExt); - TelemetryCommand response = TelemetryCommand.newBuilder() - .setRecoverOrphanedTransactionCommand( - RecoverOrphanedTransactionCommand.newBuilder() - .setOrphanedTransactionalMessage(message) - .setTransactionId(transactionId) - .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, checkData.getBrokerName())) - .build() - ).build(); - - channel.writeAndFlush(response); - if (this.checkTransactionStateHook != null) { - this.checkTransactionStateHook.beforeResponse(ctx, checkData, response, null); - } - } catch (Throwable t) { - if (this.checkTransactionStateHook != null) { - this.checkTransactionStateHook.beforeResponse(ctx, checkData, null, t); - } - } - } - - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (endTransactionHook != null) { - endTransactionHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - TransactionId handle = TransactionId.decode(request.getTransactionId()); - String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); - EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); - this.forwardProducer.endTransaction(ctx, brokerAddr, requestHeader); - future.complete(EndTransactionResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { - String topic = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - // use topic name as producerGroup - return GrpcConverter.buildEndTransactionRequestHeader(request, topic); - } - - public ResponseHook getCheckTransactionStateHook() { - return checkTransactionStateHook; - } - - public void setCheckTransactionStateHook( - ResponseHook checkTransactionStateHook) { - this.checkTransactionStateHook = checkTransactionStateHook; - } - - public ResponseHook getEndTransactionHook() { - return endTransactionHook; - } - - public void setEndTransactionHook( - ResponseHook endTransactionHook) { - this.endTransactionHook = endTransactionHook; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 0ec9913e22..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,76 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import io.netty.channel.Channel; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LocalReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { - private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ChannelManager channelManager; - private final BrokerController brokerController; - - public LocalReceiveMessageResponseStreamWriter( - StreamObserver observer, - ResponseHook hook, - ChannelManager channelManager, - BrokerController brokerController, - ReceiveMessageResultFilter receiveMessageResultFilter) { - super(observer, hook, receiveMessageResultFilter); - this.channelManager = channelManager; - this.brokerController = brokerController; - } - - @Override - protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, - Message message) { - this.changeInvisibleTime(context, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle())); - } - - private void changeInvisibleTime(Context ctx, ReceiveMessageRequest request, ReceiptHandle handle) { - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, handle); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); - command.makeCustomHeaderToNet(); - try { - brokerController.getChangeInvisibleTimeProcessor().processRequest(simpleChannelHandlerContext, command); - } catch (RemotingCommandException e) { - log.error("ChangeInvisibleTime error when write response", e); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java deleted file mode 100644 index c69aab2567..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilter.java +++ /dev/null @@ -1,94 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import io.netty.channel.Channel; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LocalReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { - private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - private final ChannelManager channelManager; - private final BrokerController brokerController; - - public LocalReceiveMessageResultFilter(ChannelManager channelManager, BrokerController brokerController, GrpcClientManager grpcClientManager) { - super(grpcClientManager); - this.channelManager = channelManager; - this.brokerController = brokerController; - } - - @Override - protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - Channel channel = channelManager.createChannel(ctx); - AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); - command.makeCustomHeaderToNet(); - try { - brokerController.getAckMessageProcessor().processRequest(new SimpleChannelHandlerContext(channel), command); - } catch (RemotingCommandException e) { - log.error("AckMessage failed in filterMessage", e); - } - } - - @Override - protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, - int maxAttempts) { - try { - ReceiptHandle handle = ReceiptHandle.create(messageExt); - if (handle == null) { - return; - } - Channel channel = channelManager.createChannel(ctx); - SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); - ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempts); - RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, consumerSendMsgBackRequestHeader); - command.makeCustomHeaderToNet(); - RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, command); - if (response.getCode() == ResponseCode.SUCCESS) { - AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); - command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, ackMessageRequestHeader); - command.makeCustomHeaderToNet(); - brokerController.getAckMessageProcessor().processRequest(simpleChannelHandlerContext, command); - } - } catch (Exception e) { - log.error("ForwardMessageToDLQ failed in filterMessage", e); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java deleted file mode 100644 index 8880b83e9c..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelector.java +++ /dev/null @@ -1,101 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.SendMessageRequest; -import com.google.common.hash.Hashing; -import io.grpc.Context; -import java.util.Random; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.broker.topic.TopicConfigManager; -import org.apache.rocketmq.common.TopicConfig; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultWriteQueueSelector; - -public class LocalWriteQueueSelector extends DefaultWriteQueueSelector { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final String brokerName; - private final AtomicInteger queueIndex; - private final TopicConfigManager topicConfigManager; - - public LocalWriteQueueSelector(String brokerName, TopicConfigManager topicConfigManager, TopicRouteCache topicRouteCache) { - super(topicRouteCache); - this.brokerName = brokerName; - this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); - this.topicConfigManager = topicConfigManager; - } - - @Override - public SelectableMessageQueue selectQueue( - Context ctx, - SendMessageRequest request - ) { - try { - if (request.getMessagesCount() <= 0) { - throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); - } - Message message = request.getMessages(0); - String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); - String shardingKey = null; - if (request.getMessagesCount() == 1) { - shardingKey = message.getSystemProperties().getMessageGroup(); - } - SelectableMessageQueue targetMessageQueue; - if (StringUtils.isNotEmpty(shardingKey)) { - // With shardingKey - targetMessageQueue = selectOrderQueue(topic, shardingKey); - } else { - targetMessageQueue = selectNormalQueue(topic); - } - return targetMessageQueue; - } catch (Exception e) { - log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); - return null; - } - } - - protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { - TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); - if (topicConfig == null) { - throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); - } - int selectQueueId = queueIndex.getAndIncrement() % topicConfig.getWriteQueueNums(); - MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); - return new SelectableMessageQueue(mq, null); - } - - protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { - TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); - if (topicConfig == null) { - throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); - } - int selectQueueId = Hashing.consistentHash(shardingKey.hashCode(), topicConfig.getWriteQueueNums()); - MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); - return new SelectableMessageQueue(mq, null); - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java deleted file mode 100644 index 7083f0684a..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteService.java +++ /dev/null @@ -1,175 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.Assignment; -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.Permission; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import com.google.common.net.HostAndPort; -import io.grpc.Context; -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.common.protocol.route.BrokerData; -import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.connector.route.TopicRouteHelper; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; - -public class RouteService extends AbstractRouteService { - public RouteService(ConnectorManager connectorManager, GrpcClientManager grpcClientManager) { - super(connectorManager, grpcClientManager); - } - - @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (queryRouteHook != null) { - queryRouteHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); - TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); - List queueDataList = topicRouteData.getQueueDatas(); - List brokerDataList = topicRouteData.getBrokerDatas(); - - List messageQueueList = new ArrayList<>(); - Map> brokerMap = buildBrokerMap(brokerDataList); - - for (QueueData queueData : queueDataList) { - String brokerName = queueData.getBrokerName(); - Map brokerIdMap = brokerMap.get(brokerName); - if (brokerIdMap == null) { - break; - } - for (Broker broker : brokerIdMap.values()) { - messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); - } - } - - QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllMessageQueues(messageQueueList) - .build(); - future.complete(response); - } catch (Throwable t) { - if (TopicRouteHelper.isTopicNotExistError(t)) { - future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) - .build()); - } else { - future.completeExceptionally(t); - } - } - return future; - } - - @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { - CompletableFuture future = new CompletableFuture<>(); - future.whenComplete((response, throwable) -> { - if (queryAssignmentHook != null) { - queryAssignmentHook.beforeResponse(ctx, request, response, throwable); - } - }); - - try { - List assignments = new ArrayList<>(); - List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); - MessageQueueWrapper messageQueueWrapper = this.connectorManager.getTopicRouteCache().getMessageQueue(topicName); - TopicRouteData topicRouteData = messageQueueWrapper.getTopicRouteData(); - Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); - for (SelectableMessageQueue messageQueue : messageQueueList) { - Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); - if (brokerIdMap != null) { - Broker broker = brokerIdMap.get(0L); - - MessageQueue defaultMessageQueue = MessageQueue.newBuilder() - .setTopic(request.getTopic()) - .setId(-1) - .setPermission(Permission.READ_WRITE) - .setBroker(broker) - .build(); - - assignments.add(Assignment.newBuilder() - .setMessageQueue(defaultMessageQueue) - .build()); - } - } - QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() - .addAllAssignments(assignments) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); - future.complete(response); - } catch (Throwable t) { - future.completeExceptionally(t); - } - return future; - } - - private Map> buildBrokerMap(List brokerDataList) { - Map> brokerMap = new HashMap<>(); - for (BrokerData brokerData : brokerDataList) { - Map brokerIdMap = new HashMap<>(); - String brokerName = brokerData.getBrokerName(); - for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { - Long brokerId = entry.getKey(); - HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); - Broker broker = Broker.newBuilder() - .setName(brokerName) - .setId(Math.toIntExact(brokerId)) - .setEndpoints(Endpoints.newBuilder() - .setScheme(AddressScheme.IPv4) - .addAddresses( - Address.newBuilder() - .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) - .setHost(hostAndPort.getHost()) - ) - .build()) - .build(); - - brokerIdMap.put(brokerId, broker); - } - brokerMap.put(brokerName, brokerIdMap); - } - return brokerMap; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java new file mode 100644 index 0000000000..35c6a02218 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -0,0 +1,74 @@ +/* + * 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.grpc.v2.transaction; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.TransactionResolution; +import apache.rocketmq.v2.TransactionSource; +import io.grpc.Context; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; +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.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.TransactionStatus; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; + +public class EndTransactionActivity extends AbstractMessingActivity { + + public EndTransactionActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager) { + super(messagingProcessor, grpcClientSettingsManager); + } + + public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + CompletableFuture future = new CompletableFuture<>(); + try { + ProxyContext context = createContext(ctx); + TransactionId transactionId = TransactionId.decode(request.getTransactionId()); + TransactionStatus transactionStatus = TransactionStatus.UNKNOWN; + TransactionResolution transactionResolution = request.getResolution(); + switch (transactionResolution) { + case COMMIT: + transactionStatus = TransactionStatus.COMMIT; + break; + case ROLLBACK: + transactionStatus = TransactionStatus.ROLLBACK; + break; + default: + break; + } + this.messagingProcessor.endTransaction( + context, + transactionId, + request.getMessageId(), + GrpcConverter.wrapResourceWithNamespace(request.getTopic()), + transactionStatus, + request.getSource().equals(TransactionSource.SOURCE_SERVER_CHECK)); + future.complete(EndTransactionResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } +} 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 new file mode 100644 index 0000000000..bf47d2d116 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/AbstractProcessor.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.processor; + +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyException; +import org.apache.rocketmq.proxy.common.ProxyExceptionCode; +import org.apache.rocketmq.proxy.service.ServiceManager; + +public abstract class AbstractProcessor { + + protected MessagingProcessor messagingProcessor; + protected ServiceManager serviceManager; + + public AbstractProcessor(MessagingProcessor messagingProcessor, + ServiceManager serviceManager) { + this.messagingProcessor = messagingProcessor; + this.serviceManager = serviceManager; + } + + protected void checkReceiptHandle(ReceiptHandle handle) { + if (handle.isExpired()) { + throw new ProxyException(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, "receipt handle is expired"); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java new file mode 100644 index 0000000000..ea6f253f8e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.processor; + +import io.netty.channel.Channel; +import java.util.Set; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.ServiceManager; + +public class ClientProcessor extends AbstractProcessor { + + public ClientProcessor(MessagingProcessor messagingProcessor, + ServiceManager serviceManager) { + super(messagingProcessor, serviceManager); + } + + public void registerProducer( + ProxyContext ctx, + String producerGroup, + ClientChannelInfo clientChannelInfo + ) { + this.serviceManager.getProducerManager().registerProducer(producerGroup, clientChannelInfo); + } + + public void unRegisterProducer( + ProxyContext ctx, + String producerGroup, + ClientChannelInfo clientChannelInfo + ) { + this.serviceManager.getProducerManager().unregisterProducer(producerGroup, clientChannelInfo); + } + + public Channel findProducerChannel( + ProxyContext ctx, + String producerGroup, + String clientId + ) { + return this.serviceManager.getProducerManager().findChannel(clientId); + } + + public void registerProducerChangeListener(ProducerChangeListener listener) { + this.serviceManager.getProducerManager().appendProducerChangeListener(listener); + } + + public void registerConsumer( + ProxyContext ctx, + String consumerGroup, + ClientChannelInfo clientChannelInfo, + ConsumeType consumeType, + MessageModel messageModel, + ConsumeFromWhere consumeFromWhere, + Set subList + ) { + this.serviceManager.getConsumerManager().registerConsumer( + consumerGroup, + clientChannelInfo, + consumeType, + messageModel, + consumeFromWhere, + subList, + false); + } + + public ClientChannelInfo findConsumerChannel( + ProxyContext ctx, + String consumerGroup, + String clientId + ) { + return this.serviceManager.getConsumerManager().findChannel(consumerGroup, clientId); + } + + public void unRegisterConsumer( + ProxyContext ctx, + String consumerGroup, + ClientChannelInfo clientChannelInfo + ) { + this.serviceManager.getConsumerManager().unregisterConsumer(consumerGroup, clientChannelInfo, false); + } + + public void registerConsumerIdsChangeListener(ConsumerIdsChangeListener listener) { + this.serviceManager.getConsumerManager().appendConsumerIdsChangeListener(listener); + } +} 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 new file mode 100644 index 0000000000..6794615544 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ConsumerProcessor.java @@ -0,0 +1,200 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +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.utils.ProxyUtils; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; + +public class ConsumerProcessor extends AbstractProcessor { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + public ConsumerProcessor(MessagingProcessor messagingProcessor, + ServiceManager serviceManager) { + super(messagingProcessor, serviceManager); + } + + public CompletableFuture popMessage( + ProxyContext ctx, + QueueSelector queueSelector, + String consumerGroup, + String topic, + int maxMsgNums, + long invisibleTime, + long pollTime, + int initMode, + SubscriptionData subscriptionData, + boolean fifo, + PopMessageResultFilter popMessageResultFilter, + long timeoutMillis + ) { + CompletableFuture future = new CompletableFuture<>(); + try { + SelectableMessageQueue messageQueue = queueSelector.select(ctx, this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); + if (messageQueue == null) { + throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no readable queue"); + } + + if (maxMsgNums > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { + log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", + maxMsgNums, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topic, consumerGroup); + maxMsgNums = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; + } + + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(topic); + requestHeader.setQueueId(messageQueue.getQueueId()); + requestHeader.setMaxMsgNums(maxMsgNums); + requestHeader.setInvisibleTime(invisibleTime); + requestHeader.setPollTime(pollTime); + requestHeader.setInitMode(initMode); + requestHeader.setExpType(subscriptionData.getExpressionType()); + requestHeader.setExp(subscriptionData.getSubString()); + requestHeader.setOrder(fifo); + + return this.serviceManager.getMessageService().popMessage( + ctx, + messageQueue, + requestHeader, + timeoutMillis) + .thenApply(popResult -> { + if (PopStatus.FOUND.equals(popResult.getPopStatus()) && + popResult.getMsgFoundList() != null && + !popResult.getMsgFoundList().isEmpty() && + popMessageResultFilter != null) { + + List messageExtList = new ArrayList<>(); + for (MessageExt messageExt : popResult.getMsgFoundList()) { + try { + PopMessageResultFilter.FilterResult filterResult = + popMessageResultFilter.filterMessage(ctx, consumerGroup, subscriptionData, messageExt); + switch (filterResult) { + case NO_MATCH: + this.messagingProcessor.ackMessage( + ctx, + ReceiptHandle.create(messageExt), + messageExt.getMsgId(), + consumerGroup, + topic, + MessagingProcessor.DEFAULT_TIMEOUT_MILLS); + break; + case TO_DLQ: + this.messagingProcessor.forwardMessageToDeadLetterQueue( + ctx, + ReceiptHandle.create(messageExt), + messageExt.getMsgId(), + consumerGroup, + topic, + MessagingProcessor.DEFAULT_TIMEOUT_MILLS); + break; + case MATCH: + default: + messageExtList.add(messageExt); + break; + } + } catch (Throwable t) { + log.error("process filterMessage failed. requestHeader:{}, msg:{}", requestHeader, messageExt, t); + messageExtList.add(messageExt); + } + } + popResult.setMsgFoundList(messageExtList); + } + return popResult; + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture ackMessage( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String consumerGroup, + String topic, + long timeoutMillis + ) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.checkReceiptHandle(handle); + + AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); + ackMessageRequestHeader.setConsumerGroup(consumerGroup); + ackMessageRequestHeader.setTopic(handle.getRealTopic(topic, consumerGroup)); + ackMessageRequestHeader.setQueueId(handle.getQueueId()); + ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); + ackMessageRequestHeader.setOffset(handle.getOffset()); + + return this.serviceManager.getMessageService().ackMessage( + ctx, + handle, + messageId, + ackMessageRequestHeader, + timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, + String messageId, String groupName, String topicName, long invisibleTime, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.checkReceiptHandle(handle); + + ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); + changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); + changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); + changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); + changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); + changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); + changeInvisibleTimeRequestHeader.setInvisibleTime(invisibleTime); + + return this.serviceManager.getMessageService().changeInvisibleTime( + ctx, + handle, + messageId, + changeInvisibleTimeRequestHeader, + timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } +} 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 new file mode 100644 index 0000000000..e89330ed76 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/DefaultMessagingProcessor.java @@ -0,0 +1,168 @@ +/* + * 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 io.netty.channel.Channel; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class DefaultMessagingProcessor implements MessagingProcessor { + + private final ServiceManager serviceManager; + private final ProducerProcessor producerProcessor; + private final ConsumerProcessor consumerProcessor; + private final TransactionProcessor transactionProcessor; + private final ClientProcessor clientProcessor; + + public DefaultMessagingProcessor(ServiceManager serviceManager) { + this.serviceManager = serviceManager; + this.producerProcessor = new ProducerProcessor(this, serviceManager); + this.consumerProcessor = new ConsumerProcessor(this, serviceManager); + this.transactionProcessor = new TransactionProcessor(this, serviceManager); + this.clientProcessor = new ClientProcessor(this, serviceManager); + } + + @Override + public ProxyTopicRouteData getTopicRouteDataForProxy(ProxyContext ctx, List
requestHostAndPortList, + String topicName) throws Exception { + return this.serviceManager.getTopicRouteService().getTopicRouteForProxy(requestHostAndPortList, topicName); + } + + @Override + public CompletableFuture sendMessage(ProxyContext ctx, QueueSelector queueSelector, + String producerGroup, List msg, long timeoutMillis) { + return this.producerProcessor.sendMessage(ctx, queueSelector, producerGroup, msg, timeoutMillis); + } + + @Override + public CompletableFuture forwardMessageToDeadLetterQueue(ProxyContext ctx, ReceiptHandle handle, + String messageId, String groupName, String topicName, long timeoutMillis) { + return this.producerProcessor.forwardMessageToDeadLetterQueue(ctx, handle, messageId, groupName, topicName, timeoutMillis); + } + + @Override + public void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId, + String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + this.transactionProcessor.endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, timeoutMillis); + } + + @Override + public CompletableFuture popMessage( + ProxyContext ctx, + QueueSelector queueSelector, + String consumerGroup, + String topic, + int maxMsgNums, + long invisibleTime, + long pollTime, + int initMode, + SubscriptionData subscriptionData, + boolean fifo, + PopMessageResultFilter popMessageResultFilter, + long timeoutMillis + ) { + return this.consumerProcessor.popMessage(ctx, queueSelector, consumerGroup, topic, maxMsgNums, + invisibleTime, pollTime, initMode, subscriptionData, fifo, popMessageResultFilter, timeoutMillis); + } + + @Override + public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, + String consumerGroup, String topic, long timeoutMillis) { + return this.consumerProcessor.ackMessage(ctx, handle, messageId, consumerGroup, topic, timeoutMillis); + } + + @Override + public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, String messageId, + String groupName, String topicName, long invisibleTime, long timeoutMillis) { + return this.consumerProcessor.changeInvisibleTime(ctx, handle, messageId, groupName, topicName, invisibleTime, timeoutMillis); + } + + @Override + public void registerProducer(ProxyContext ctx, String producerGroup, ClientChannelInfo clientChannelInfo) { + this.clientProcessor.registerProducer(ctx, producerGroup, clientChannelInfo); + } + + @Override + public void unRegisterProducer(ProxyContext ctx, String producerGroup, ClientChannelInfo clientChannelInfo) { + this.clientProcessor.unRegisterProducer(ctx, producerGroup, clientChannelInfo); + } + + @Override + public Channel findProducerChannel(ProxyContext ctx, String producerGroup, String clientId) { + return this.clientProcessor.findProducerChannel(ctx, producerGroup, clientId); + } + + @Override + public void registerProducerListener(ProducerChangeListener producerChangeListener) { + this.clientProcessor.registerProducerChangeListener(producerChangeListener); + } + + @Override + public void registerConsumer(ProxyContext ctx, String consumerGroup, ClientChannelInfo clientChannelInfo, + ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, + Set subList) { + this.clientProcessor.registerConsumer(ctx, consumerGroup, clientChannelInfo, consumeType, messageModel, consumeFromWhere, subList); + } + + @Override + public ClientChannelInfo findConsumerChannel(ProxyContext ctx, String consumerGroup, String clientId) { + return this.clientProcessor.findConsumerChannel(ctx, consumerGroup, clientId); + } + + @Override + public void unRegisterConsumer(ProxyContext ctx, String consumerGroup, ClientChannelInfo clientChannelInfo) { + this.clientProcessor.unRegisterConsumer(ctx, consumerGroup, clientChannelInfo); + } + + @Override + public void registerConsumerListener(ConsumerIdsChangeListener consumerIdsChangeListener) { + this.clientProcessor.registerConsumerIdsChangeListener(consumerIdsChangeListener); + } + + @Override + public void addTransactionSubscription(ProxyContext ctx, String producerGroup, String topic) { + this.transactionProcessor.addTransactionSubscription(ctx, producerGroup, topic); + } + + @Override + public ProxyOutService getProxyOutService() { + return this.serviceManager.getProxyOutService(); + } + +} 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 new file mode 100644 index 0000000000..9fdb8afc4b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/MessagingProcessor.java @@ -0,0 +1,222 @@ +/* + * 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 io.netty.channel.Channel; +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public interface MessagingProcessor { + + long DEFAULT_TIMEOUT_MILLS = Duration.ofSeconds(2).toMillis(); + + ProxyTopicRouteData getTopicRouteDataForProxy( + ProxyContext ctx, + List
requestHostAndPortList, + String topicName + ) throws Exception; + + default CompletableFuture sendMessage( + ProxyContext ctx, + QueueSelector queueSelector, + String producerGroup, + List msg + ) { + return sendMessage(ctx, queueSelector, producerGroup, msg, DEFAULT_TIMEOUT_MILLS); + } + + CompletableFuture sendMessage( + ProxyContext ctx, + QueueSelector queueSelector, + String producerGroup, + List msg, + long timeoutMillis + ); + + default CompletableFuture forwardMessageToDeadLetterQueue( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String groupName, + String topicName + ) { + return forwardMessageToDeadLetterQueue(ctx, handle, messageId, groupName, topicName, DEFAULT_TIMEOUT_MILLS); + } + + CompletableFuture forwardMessageToDeadLetterQueue( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String groupName, + String topicName, + long timeoutMillis + ); + + default void endTransaction( + ProxyContext ctx, + TransactionId transactionId, + String messageId, + String producerGroup, + TransactionStatus transactionStatus, + boolean fromTransactionCheck + ) throws MQBrokerException, RemotingException, InterruptedException { + endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, DEFAULT_TIMEOUT_MILLS); + } + + void endTransaction( + ProxyContext ctx, + TransactionId transactionId, + String messageId, + String producerGroup, + TransactionStatus transactionStatus, + boolean fromTransactionCheck, + long timeoutMillis + ) throws MQBrokerException, RemotingException, InterruptedException; + + CompletableFuture popMessage( + ProxyContext ctx, + QueueSelector queueSelector, + String consumerGroup, + String topic, + int maxMsgNums, + long invisibleTime, + long pollTime, + int initMode, + SubscriptionData subscriptionData, + boolean fifo, + PopMessageResultFilter popMessageResultFilter, + long timeoutMillis + ); + + default CompletableFuture ackMessage( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String consumerGroup, + String topic + ) { + return ackMessage(ctx, handle, messageId, consumerGroup, topic, DEFAULT_TIMEOUT_MILLS); + } + + CompletableFuture ackMessage( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String consumerGroup, + String topic, + long timeoutMillis + ); + + default CompletableFuture changeInvisibleTime( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String groupName, + String topicName, + long invisibleTime + ) { + return changeInvisibleTime(ctx, handle, messageId, groupName, topicName, invisibleTime, DEFAULT_TIMEOUT_MILLS); + } + + CompletableFuture changeInvisibleTime( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + String groupName, + String topicName, + long invisibleTime, + long timeoutMillis + ); + + void registerProducer( + ProxyContext ctx, + String producerGroup, + ClientChannelInfo clientChannelInfo + ); + + void unRegisterProducer( + ProxyContext ctx, + String producerGroup, + ClientChannelInfo clientChannelInfo + ); + + Channel findProducerChannel( + ProxyContext ctx, + String producerGroup, + String clientId + ); + + void registerProducerListener( + ProducerChangeListener producerChangeListener + ); + + void registerConsumer( + ProxyContext ctx, + String consumerGroup, + ClientChannelInfo clientChannelInfo, + ConsumeType consumeType, + MessageModel messageModel, + ConsumeFromWhere consumeFromWhere, + Set subList + ); + + ClientChannelInfo findConsumerChannel( + ProxyContext ctx, + String consumerGroup, + String clientId + ); + + void unRegisterConsumer( + ProxyContext ctx, + String consumerGroup, + ClientChannelInfo clientChannelInfo + ); + + void registerConsumerListener( + ConsumerIdsChangeListener consumerIdsChangeListener + ); + + void addTransactionSubscription( + ProxyContext ctx, + String producerGroup, + String topic + ); + + ProxyOutService getProxyOutService(); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/PopMessageResultFilter.java similarity index 62% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/processor/PopMessageResultFilter.java index 3eb936437a..328ae94e30 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ReadQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/PopMessageResultFilter.java @@ -14,14 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.processor; -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.ProxyContext; -public interface ReadQueueSelector { +public interface PopMessageResultFilter { - SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader); + enum FilterResult { + TO_DLQ, + NO_MATCH, + MATCH + } + + FilterResult filterMessage(ProxyContext ctx, String consumerGroup, SubscriptionData subscriptionData, + MessageExt messageExt); } 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 new file mode 100644 index 0000000000..dfd6395e59 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ProducerProcessor.java @@ -0,0 +1,136 @@ +/* + * 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 java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +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.service.ServiceManager; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ProducerProcessor extends AbstractProcessor { + + public ProducerProcessor(MessagingProcessor messagingProcessor, + ServiceManager serviceManager) { + super(messagingProcessor, serviceManager); + } + + public CompletableFuture sendMessage(ProxyContext ctx, QueueSelector queueSelector, + String producerGroup, List messageExtList, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + String topic = messageExtList.get(0).getTopic(); + SelectableMessageQueue messageQueue = queueSelector.select(ctx, + this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); + if (messageQueue == null) { + throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no writable queue"); + } + + SendMessageRequestHeader requestHeader = buildSendMessageRequestHeader(messageExtList, producerGroup, messageQueue.getQueueId()); + + return this.serviceManager.getMessageService().sendMessage( + ctx, + messageQueue, + messageExtList, + requestHeader, + timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + + protected SendMessageRequestHeader buildSendMessageRequestHeader(List messageExtList, + String producerGroup, int queueId) { + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + + MessageExt message = messageExtList.get(0); + + requestHeader.setProducerGroup(producerGroup); + requestHeader.setTopic(message.getTopic()); + requestHeader.setDefaultTopic(""); + requestHeader.setDefaultTopicQueueNums(0); + requestHeader.setQueueId(queueId); + requestHeader.setSysFlag(message.getSysFlag()); + requestHeader.setBornTimestamp(System.currentTimeMillis()); + requestHeader.setFlag(message.getFlag()); + requestHeader.setProperties(MessageDecoder.messageProperties2String(message.getProperties())); + requestHeader.setReconsumeTimes(0); + if (messageExtList.size() > 1) { + requestHeader.setBatch(true); + } + if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { + String reconsumeTimes = MessageAccessor.getReconsumeTime(message); + if (reconsumeTimes != null) { + requestHeader.setReconsumeTimes(Integer.valueOf(reconsumeTimes)); + MessageAccessor.clearProperty(message, MessageConst.PROPERTY_RECONSUME_TIME); + } + + String maxReconsumeTimes = MessageAccessor.getMaxReconsumeTimes(message); + if (maxReconsumeTimes != null) { + requestHeader.setMaxReconsumeTimes(Integer.valueOf(maxReconsumeTimes)); + MessageAccessor.clearProperty(message, MessageConst.PROPERTY_MAX_RECONSUME_TIMES); + } + } + + return requestHeader; + } + + public CompletableFuture forwardMessageToDeadLetterQueue(ProxyContext ctx, ReceiptHandle handle, + String messageId, String groupName, String topicName, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); + consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); + consumerSendMsgBackRequestHeader.setGroup(groupName); + consumerSendMsgBackRequestHeader.setDelayLevel(-1); + consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); + consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); + consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(0); + + return this.serviceManager.getMessageService().sendMessageBack( + ctx, + handle, + messageId, + consumerSendMsgBackRequestHeader, + timeoutMillis + ).whenComplete((remotingCommand, t) -> { + if (t == null && remotingCommand.getCode() == ResponseCode.SUCCESS) { + this.messagingProcessor.ackMessage(ctx, handle, messageId, + groupName, topicName, timeoutMillis); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java similarity index 67% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java index 5151225904..ae6d66d9bb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/AssignmentQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +package org.apache.rocketmq.proxy.processor; -import apache.rocketmq.v2.QueryAssignmentRequest; -import io.grpc.Context; -import java.util.List; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -public interface AssignmentQueueSelector { +public interface QueueSelector { - List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception; + SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java new file mode 100644 index 0000000000..d548271f9d --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.processor; + +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.exception.RemotingException; + +public class TransactionProcessor extends AbstractProcessor { + + public TransactionProcessor(MessagingProcessor messagingProcessor, + ServiceManager serviceManager) { + super(messagingProcessor, serviceManager); + } + + void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId,String producerGroup, + TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + + EndTransactionRequestHeader requestHeader = buildEndTransactionRequestHeader(transactionId, messageId, + producerGroup, transactionStatus, fromTransactionCheck); + this.serviceManager.getMessageService().endTransactionOneway( + ctx, + transactionId, + requestHeader, + timeoutMillis + ); + } + + protected EndTransactionRequestHeader buildEndTransactionRequestHeader(TransactionId transactionId, String messageId,String producerGroup, + TransactionStatus transactionStatus, boolean fromTransactionCheck) { + long transactionStateTableOffset = transactionId.getTranStateTableOffset(); + long commitLogOffset = transactionId.getCommitLogOffset(); + + int commitOrRollback; + switch (transactionStatus) { + case COMMIT: + commitOrRollback = MessageSysFlag.TRANSACTION_COMMIT_TYPE; + break; + case ROLLBACK: + commitOrRollback = MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; + break; + default: + commitOrRollback = MessageSysFlag.TRANSACTION_NOT_TYPE; + break; + } + + EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); + endTransactionRequestHeader.setProducerGroup(producerGroup); + endTransactionRequestHeader.setMsgId(messageId); + endTransactionRequestHeader.setTransactionId(transactionId.getBrokerTransactionId()); + endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); + endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); + endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); + endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); + + return endTransactionRequestHeader; + } + + public void addTransactionSubscription(ProxyContext ctx, String producerGroup, String topic) { + this.serviceManager.getTransactionService().addTransactionSubscription(producerGroup, topic); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionStatus.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionStatus.java new file mode 100644 index 0000000000..e456a6061a --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionStatus.java @@ -0,0 +1,23 @@ +/* + * 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; + +public enum TransactionStatus { + UNKNOWN, + COMMIT, + ROLLBACK +} 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 new file mode 100644 index 0000000000..4a548883f2 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ClusterServiceManager.java @@ -0,0 +1,152 @@ +/* + * 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.service; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerChangeListener; +import org.apache.rocketmq.broker.client.ProducerGroupEvent; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.message.ClusterMessageService; +import org.apache.rocketmq.proxy.service.message.MessageService; +import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.out.ClusterProxyOutService; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.ClusterTopicRouteService; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; +import org.apache.rocketmq.remoting.RPCHook; + +public class ClusterServiceManager extends ServiceManager { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + private final ClusterTransactionService clusterTransactionService; + private final ProducerManager producerManager; + private final ConsumerManager consumerManager; + private final TopicRouteService topicRouteService; + private final MessageService messageService; + private final ProxyOutService proxyOutService; + + private final ScheduledExecutorService scheduledExecutorService; + private final MQClientAPIFactory mqClientAPIFactory; + + public ClusterServiceManager(RPCHook rpcHook) { + this.scheduledExecutorService = Executors.newScheduledThreadPool(3); + this.producerManager = new ProducerManager(); + this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); + + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + double workerFactor = proxyConfig.getRocketmqMQClientWorkerFactor(); + int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); + this.mqClientAPIFactory = new MQClientAPIFactory( + "CLUSTER_MQ_CLIENT_", + proxyConfig.getRocketmqMQClientNum(), + threadCount, + new DoNothingClientRemotingProcessor(null), + rpcHook, + scheduledExecutorService); + + this.topicRouteService = new ClusterTopicRouteService(rpcHook); + this.messageService = new ClusterMessageService(this.topicRouteService, this.mqClientAPIFactory); + this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook); + this.proxyOutService = new ClusterProxyOutService(); + + this.init(); + } + + protected void init() { + this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); + + this.scheduledExecutorService.scheduleAtFixedRate(() -> { + try { + producerManager.scanNotActiveChannel(); + consumerManager.scanNotActiveChannel(); + } catch (Throwable e) { + log.error("Error occurred when scan not active client channels.", e); + } + }, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); + + this.appendShutdown(scheduledExecutorService::shutdown); + this.appendStartAndShutdown(this.mqClientAPIFactory); + this.appendStartAndShutdown(this.topicRouteService); + this.appendStartAndShutdown(this.clusterTransactionService); + } + + @Override + public MessageService getMessageService() { + return this.messageService; + } + + @Override + public TopicRouteService getTopicRouteService() { + return topicRouteService; + } + + @Override + public ProducerManager getProducerManager() { + return this.producerManager; + } + + @Override + public ConsumerManager getConsumerManager() { + return this.consumerManager; + } + + @Override + public TransactionService getTransactionService() { + return this.clusterTransactionService; + } + + @Override + public ProxyOutService getProxyOutService() { + return this.proxyOutService; + } + + protected static class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { + + @Override + public void handle(ConsumerGroupEvent event, String group, Object... args) { + + } + + @Override + public void shutdown() { + + } + } + + protected class ProducerChangeListenerImpl implements ProducerChangeListener { + @Override + public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { + if (event == ProducerGroupEvent.GROUP_UNREGISTER) { + getTransactionService().unSubscribeAllTransactionTopic(group); + } + } + } +} 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 new file mode 100644 index 0000000000..97549a6eb0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/LocalServiceManager.java @@ -0,0 +1,84 @@ +/* + * 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.service; + +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.proxy.service.message.LocalMessageService; +import org.apache.rocketmq.proxy.service.message.MessageService; +import org.apache.rocketmq.proxy.service.out.LocalProxyOutService; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.LocalTopicRouteService; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.LocalTransactionService; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; +import org.apache.rocketmq.remoting.RPCHook; + +public class LocalServiceManager extends ServiceManager { + + private final BrokerController brokerController; + private final TopicRouteService topicRouteService; + private final MessageService messageService; + private final TransactionService transactionService; + private final ProxyOutService proxyOutService; + + public LocalServiceManager(BrokerController brokerController, RPCHook rpcHook) { + this.brokerController = brokerController; + this.messageService = new LocalMessageService(brokerController, rpcHook); + this.topicRouteService = new LocalTopicRouteService(brokerController, rpcHook); + this.transactionService = new LocalTransactionService(); + this.proxyOutService = new LocalProxyOutService(brokerController); + + this.init(); + } + + protected void init() { + this.appendStartAndShutdown(this.topicRouteService); + } + + @Override + public MessageService getMessageService() { + return this.messageService; + } + + @Override + public TopicRouteService getTopicRouteService() { + return this.topicRouteService; + } + + @Override + public ProducerManager getProducerManager() { + return this.brokerController.getProducerManager(); + } + + @Override + public ConsumerManager getConsumerManager() { + return this.brokerController.getConsumerManager(); + } + + @Override + public TransactionService getTransactionService() { + return this.transactionService; + } + + @Override + public ProxyOutService getProxyOutService() { + return this.proxyOutService; + } + +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java new file mode 100644 index 0000000000..820d99444b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -0,0 +1,58 @@ +/* + * 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.service; + +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.service.message.MessageService; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; +import org.apache.rocketmq.remoting.RPCHook; + +public abstract class ServiceManager extends AbstractStartAndShutdown { + + public static ServiceManager createForLocalMode(BrokerController brokerController) { + return createForLocalMode(brokerController, null); + } + + public static ServiceManager createForLocalMode(BrokerController brokerController, RPCHook rpcHook) { + return new LocalServiceManager(brokerController, rpcHook); + } + + public static ServiceManager createForClusterMode() { + return createForClusterMode(null); + } + + public static ServiceManager createForClusterMode(RPCHook rpcHook) { + return new ClusterServiceManager(rpcHook); + } + + public abstract MessageService getMessageService(); + + public abstract TopicRouteService getTopicRouteService(); + + public abstract ProducerManager getProducerManager(); + + public abstract ConsumerManager getConsumerManager(); + + public abstract TransactionService getTransactionService(); + + public abstract ProxyOutService getProxyOutService(); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java new file mode 100644 index 0000000000..b7aa35ae84 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java @@ -0,0 +1,44 @@ +/* + * 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.service.message; + +import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; + +public abstract class AbstractMessageService implements MessageService { + + protected CompletableFuture processSendMessageResponseFuture( + String brokerName, + SendMessageRequestHeader requestHeader, + CompletableFuture future) { + return future.thenApply(sendResult -> { + int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && + tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && + StringUtils.isNotBlank(sendResult.getTransactionId())) { + TransactionId transactionId = TransactionId.genByBrokerTransactionId(brokerName, sendResult); + sendResult.setTransactionId(transactionId.getProxyTransactionId()); + } + return sendResult; + }); + } +} 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 new file mode 100644 index 0000000000..b48cade6da --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/ClusterMessageService.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.message; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +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.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class ClusterMessageService extends AbstractMessageService { + + private final TopicRouteService topicRouteService; + private final MQClientAPIFactory mqClientAPIFactory; + + public ClusterMessageService(TopicRouteService topicRouteService, MQClientAPIFactory mqClientAPIFactory) { + this.topicRouteService = topicRouteService; + this.mqClientAPIFactory = mqClientAPIFactory; + } + + @Override + public CompletableFuture sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { + CompletableFuture future; + if (msgList.size() == 1) { + future = this.mqClientAPIFactory.getClient().sendMessageAsync( + messageQueue.getBrokerAddr(), + messageQueue.getBrokerName(), msgList.get(0), requestHeader, timeoutMillis); + } else { + future = this.mqClientAPIFactory.getClient().sendMessageAsync( + messageQueue.getBrokerAddr(), + messageQueue.getBrokerName(), msgList, requestHeader, timeoutMillis); + } + return processSendMessageResponseFuture(messageQueue.getBrokerName(), requestHeader, future); + } + + @Override + public CompletableFuture sendMessageBack(ProxyContext ctx, ReceiptHandle handle, String messageId, + ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().sendMessageBackAsync( + this.resolveBrokerAddr(handle), + requestHeader, + timeoutMillis + ); + } + + @Override + public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, + EndTransactionRequestHeader requestHeader, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + this.mqClientAPIFactory.getClient().endTransactionOneway( + this.resolveBrokerAddr(transactionId.getBrokerName()), + requestHeader, + "end transaction from proxy", + timeoutMillis + ); + } + + @Override + public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + PopMessageRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().popMessageAsync( + messageQueue.getBrokerAddr(), + messageQueue.getBrokerName(), + requestHeader, + timeoutMillis + ); + } + + @Override + public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, String messageId, + ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().changeInvisibleTimeAsync( + this.resolveBrokerAddr(handle), + handle.getBrokerName(), + requestHeader, + timeoutMillis + ); + } + + @Override + public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, + AckMessageRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().ackMessageAsync( + this.resolveBrokerAddr(handle), + requestHeader, + timeoutMillis + ); + } + + protected String resolveBrokerAddr(ReceiptHandle handle) { + return resolveBrokerAddr(handle.getBrokerName()); + } + + protected String resolveBrokerAddr(String brokerName) { + try { + return this.topicRouteService.getBrokerAddr(brokerName); + } catch (Throwable t) { + throw new ProxyException(ProxyExceptionCode.INVALID_BROKER_NAME, "broker " + brokerName + " cannot find", t); + } + } +} 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 new file mode 100644 index 0000000000..e8ff4a353c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalMessageService.java @@ -0,0 +1,78 @@ +/* + * 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.service.message; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class LocalMessageService extends AbstractMessageService { + + private BrokerController brokerController; + + public LocalMessageService(BrokerController brokerController, RPCHook rpcHook) { + this.brokerController = brokerController; + } + + @Override public CompletableFuture sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { + return null; + } + + @Override + public CompletableFuture sendMessageBack(ProxyContext ctx, ReceiptHandle handle, String messageId, + ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { + return null; + } + + @Override public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, + EndTransactionRequestHeader requestHeader, long timeoutMillis) { + + } + + @Override public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + PopMessageRequestHeader requestHeader, long timeoutMillis) { + return null; + } + + @Override + public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, String messageId, + ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { + return null; + } + + @Override public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, + AckMessageRequestHeader requestHeader, long timeoutMillis) { + return null; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java similarity index 51% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java index 450c611bd7..8f833d4c99 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/factory/MQClientFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java @@ -14,21 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.factory; +package org.apache.rocketmq.proxy.service.message; -import java.util.concurrent.ScheduledExecutorService; -import org.apache.rocketmq.client.impl.ClientRemotingProcessor; -import org.apache.rocketmq.proxy.connector.processor.DoNothingClientRemotingProcessor; -import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.CommandCustomHeader; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class MQClientFactory extends AbstractMQClientFactory { +public class LocalRemotingCommand extends RemotingCommand { - public MQClientFactory(ScheduledExecutorService scheduledExecutorService, RPCHook rpcHook) { - super(scheduledExecutorService, rpcHook); + public static LocalRemotingCommand createRequestCommand(int code, CommandCustomHeader customHeader) { + LocalRemotingCommand cmd = new LocalRemotingCommand(); + cmd.setCode(code); + cmd.writeCustomHeader(customHeader); + setCmdVersion(cmd); + return cmd; } @Override - protected ClientRemotingProcessor createClientRemotingProcessor() { - return new DoNothingClientRemotingProcessor(null); + public T decodeCommandCustomHeader( + Class classHeader) throws RemotingCommandException { + return classHeader.cast(readCustomHeader()); } } 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 new file mode 100644 index 0000000000..4d42c317cb --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/MessageService.java @@ -0,0 +1,86 @@ +/* + * 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.service.message; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public interface MessageService { + + CompletableFuture sendMessage( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + List msgList, + SendMessageRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture sendMessageBack( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + ConsumerSendMsgBackRequestHeader requestHeader, + long timeoutMillis + ); + + void endTransactionOneway( + ProxyContext ctx, + TransactionId transactionId, + EndTransactionRequestHeader requestHeader, + long timeoutMillis + ) throws MQBrokerException, RemotingException, InterruptedException; + + CompletableFuture popMessage( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + PopMessageRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture changeInvisibleTime( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + ChangeInvisibleTimeRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture ackMessage( + ProxyContext ctx, + ReceiptHandle handle, + String messageId, + AckMessageRequestHeader requestHeader, + long timeoutMillis + ); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/DoNothingClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/DoNothingClientRemotingProcessor.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/DoNothingClientRemotingProcessor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/DoNothingClientRemotingProcessor.java index 05d2e19deb..5d2be52ab3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/DoNothingClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/DoNothingClientRemotingProcessor.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.processor; +package org.apache.rocketmq.proxy.service.mqclient; import io.netty.channel.ChannelHandlerContext; import org.apache.rocketmq.client.impl.ClientRemotingProcessor; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java similarity index 95% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 47e204e579..8826c188a1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/client/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.client; +package org.apache.rocketmq.proxy.service.mqclient; import java.nio.ByteBuffer; import java.util.Collections; @@ -60,7 +60,11 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; import org.apache.rocketmq.remoting.exception.RemotingException; +import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -102,6 +106,17 @@ public class MQClientAPIExt extends MQClientAPIImpl { return ex; } + public void sendHeartbeatOneway( + String brokerAddr, + HeartbeatData heartbeatData, + long timeoutMillis + ) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, RemotingTooMuchRequestException { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); + request.setLanguage(clientConfig.getLanguage()); + request.setBody(heartbeatData.encode()); + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + } + public CompletableFuture sendHeartbeatAsync( String brokerAddr, HeartbeatData heartbeatData, @@ -164,7 +179,7 @@ public class MQClientAPIExt extends MQClientAPIImpl { public CompletableFuture sendMessageAsync( String brokerAddr, String brokerName, - List msgList, + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis ) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java new file mode 100644 index 0000000000..b9e17d228b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.mqclient; + +import java.time.Duration; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.impl.ClientRemotingProcessor; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; + +public class MQClientAPIFactory implements StartAndShutdown { + + private MQClientAPIExt[] clients; + private final String namePrefix; + private final int clientNum; + private final int bootstrapWorkerThreads; + private final ClientRemotingProcessor clientRemotingProcessor; + private final RPCHook rpcHook; + private final ScheduledExecutorService scheduledExecutorService; + + public MQClientAPIFactory(String namePrefix, int clientNum, int bootstrapWorkerThreads, + ClientRemotingProcessor clientRemotingProcessor, + RPCHook rpcHook, ScheduledExecutorService scheduledExecutorService) { + this.namePrefix = namePrefix; + this.clientNum = clientNum; + this.bootstrapWorkerThreads = bootstrapWorkerThreads; + this.clientRemotingProcessor = clientRemotingProcessor; + this.rpcHook = rpcHook; + this.scheduledExecutorService = scheduledExecutorService; + + this.init(); + } + + protected void init() { + System.setProperty(ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false"); + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + if (StringUtils.isEmpty(proxyConfig.getNameSrvDomain())) { + System.setProperty(MixAll.NAMESRV_ADDR_PROPERTY, proxyConfig.getNameSrvAddr()); + } else { + System.setProperty("rocketmq.namesrv.domain", proxyConfig.getNameSrvDomain()); + System.setProperty("rocketmq.namesrv.domain.subgroup", proxyConfig.getNameSrvDomainSubgroup()); + } + } + + public MQClientAPIExt getClient() { + if (clients.length == 1) { + return this.clients[0]; + } + int index = ThreadLocalRandom.current().nextInt(this.clients.length); + return this.clients[index]; + } + + @Override + public void start() throws Exception { + this.clients = new MQClientAPIExt[this.clientNum]; + + for (int i = 0; i < this.clientNum; i++) { + clients[i] = createAndStart(this.namePrefix + "N_" + i); + } + } + + @Override + public void shutdown() throws Exception { + for (int i = 0; i < this.clientNum; i++) { + clients[i].shutdown(); + } + } + + protected MQClientAPIExt createAndStart(String instanceName) { + ClientConfig clientConfig = new ClientConfig(); + clientConfig.setInstanceName(instanceName); + + NettyClientConfig nettyClientConfig = new NettyClientConfig(); + nettyClientConfig.setBootstrapWorkerThreads(bootstrapWorkerThreads); + nettyClientConfig.setDisableNettyWorkerGroup(true); + nettyClientConfig.setDisableCallbackExecutor(true); + + MQClientAPIExt mqClientAPIExt = new MQClientAPIExt(clientConfig, nettyClientConfig, + clientRemotingProcessor, + rpcHook); + + if (!mqClientAPIExt.updateNameServerAddressList()) { + this.scheduledExecutorService.scheduleAtFixedRate( + mqClientAPIExt::fetchNameServerAddr, + Duration.ofSeconds(10).toMillis(), + Duration.ofMinutes(2).toMillis(), + TimeUnit.MILLISECONDS + ); + } + mqClientAPIExt.start(); + return mqClientAPIExt; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java similarity index 59% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java index 3c03488916..ca3edf3ef7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/processor/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java @@ -14,28 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.processor; +package org.apache.rocketmq.proxy.service.mqclient; import io.netty.channel.ChannelHandlerContext; import java.nio.ByteBuffer; +import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.client.impl.ClientRemotingProcessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { - private final TransactionStateChecker transactionStateChecker; + private final ProducerManager producerManager; - public ProxyClientRemotingProcessor(TransactionStateChecker transactionStateChecker) { + public ProxyClientRemotingProcessor(ProducerManager producerManager) { super(null); - this.transactionStateChecker = transactionStateChecker; + this.producerManager = producerManager; } @Override @@ -48,30 +46,16 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { } @Override - public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, RemotingCommand request) - throws RemotingCommandException { - final CheckTransactionStateRequestHeader requestHeader = - (CheckTransactionStateRequestHeader) request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { final ByteBuffer byteBuffer = ByteBuffer.wrap(request.getBody()); final MessageExt messageExt = MessageDecoder.decode(byteBuffer, true, false, false); if (messageExt != null) { final String group = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); if (group != null) { - transactionStateChecker.checkTransactionState( - new TransactionStateCheckRequest( - group, - requestHeader.getTranStateTableOffset(), - requestHeader.getCommitLogOffset(), - requestHeader.getMsgId(), - TransactionId.genByBrokerTransactionId( - ctx.channel().remoteAddress(), - requestHeader.getTransactionId(), - requestHeader.getCommitLogOffset(), - requestHeader.getTranStateTableOffset()), - requestHeader.getBrokerName(), - messageExt - ) - ); + CheckTransactionStateRequestHeader requestHeader = + request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); + request.writeCustomHeader(requestHeader); + this.producerManager.getAvailableChannel(group).writeAndFlush(request); } } return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java new file mode 100644 index 0000000000..4e4e6e36c6 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.out; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +/** + * not implement yet + */ +public class ClusterProxyOutService implements ProxyOutService { + + @Override + public CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + GetConsumerRunningInfoRequestHeader header) { + return new CompletableFuture<>(); + } + + @Override + public CompletableFuture processConsumeMessageDirectly(RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header) { + return new CompletableFuture<>(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java new file mode 100644 index 0000000000..1b3d5baed8 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java @@ -0,0 +1,63 @@ +/* + * 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.service.out; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.remoting.RemotingServer; +import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class LocalProxyOutService implements ProxyOutService { + + private final BrokerController brokerController; + + public LocalProxyOutService(BrokerController brokerController) { + this.brokerController = brokerController; + } + + @Override + public CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + GetConsumerRunningInfoRequestHeader header) { + CompletableFuture future = new CompletableFuture<>(); + future.thenAccept(consumerRunningInfo -> { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "from gRPC client"); + remotingCommand.setOpaque(command.getOpaque()); + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(consumerRunningInfo.getJstack()); + remotingCommand.setBody(runningInfo.encode()); + + // nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); + } + }); + return future; + } + + @Override + public CompletableFuture processConsumeMessageDirectly(RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header) { + return null; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java new file mode 100644 index 0000000000..a085013096 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java @@ -0,0 +1,171 @@ +/* + * 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.service.out; + +import io.netty.channel.AbstractChannel; +import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelId; +import io.netty.channel.ChannelMetadata; +import io.netty.channel.ChannelOutboundBuffer; +import io.netty.channel.DefaultChannelPromise; +import io.netty.channel.EventLoop; +import io.netty.util.concurrent.GlobalEventExecutor; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public abstract class ProxyChannel extends AbstractChannel { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + protected final ProxyOutService proxyOutService; + + protected ProxyChannel(ProxyOutService proxyOutService, Channel parent) { + super(parent); + this.proxyOutService = proxyOutService; + } + + protected ProxyChannel(ProxyOutService proxyOutService, Channel parent, ChannelId id) { + super(parent, id); + this.proxyOutService = proxyOutService; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + CompletableFuture processFuture = new CompletableFuture<>(); + + try { + if (msg instanceof RemotingCommand) { + RemotingCommand command = (RemotingCommand) msg; + switch (command.getCode()) { + case RequestCode.CHECK_TRANSACTION_STATE: { + CheckTransactionStateRequestHeader header = (CheckTransactionStateRequestHeader) command.readCustomHeader(); + MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); + TransactionId transactionId = TransactionId.genByBrokerTransactionId(header.getBrokerName(), + header.getTransactionId(), messageExt.getCommitLogOffset(), messageExt.getQueueOffset()); + processFuture = this.processCheckTransaction(header, messageExt, transactionId); + break; + } + case RequestCode.GET_CONSUMER_RUNNING_INFO: { + GetConsumerRunningInfoRequestHeader header = (GetConsumerRunningInfoRequestHeader) command.readCustomHeader(); + processFuture = this.processGetConsumerRunningInfo(command, header, + this.proxyOutService.processGetConsumerRunningInfo(command, header)); + break; + } + case RequestCode.CONSUME_MESSAGE_DIRECTLY: { + ConsumeMessageDirectlyResultRequestHeader header = (ConsumeMessageDirectlyResultRequestHeader) command.readCustomHeader(); + MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); + processFuture = this.processConsumeMessageDirectly(command, header, messageExt, + this.proxyOutService.processConsumeMessageDirectly(command, header)); + break; + } + default: + break; + } + } else { + processFuture = processOtherMessage(msg); + } + } catch (Throwable t) { + log.error("process failed. msg:{}", msg, t); + processFuture.completeExceptionally(t); + } + + DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); + processFuture.thenAccept(ignore -> promise.setSuccess()) + .exceptionally(t -> { + promise.setFailure(t); + return null; + }); + return promise; + } + + protected abstract CompletableFuture processOtherMessage(Object msg); + + protected abstract CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, + MessageExt messageExt, TransactionId transactionId); + + protected abstract CompletableFuture processGetConsumerRunningInfo( + RemotingCommand command, + GetConsumerRunningInfoRequestHeader header, + CompletableFuture responseFuture); + + protected abstract CompletableFuture processConsumeMessageDirectly( + RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header, + MessageExt messageExt, + CompletableFuture responseFuture); + + @Override + public ChannelConfig config() { + return null; + } + + @Override + public ChannelMetadata metadata() { + return null; + } + + @Override + protected AbstractUnsafe newUnsafe() { + return null; + } + + @Override + protected boolean isCompatible(EventLoop loop) { + return false; + } + + @Override + protected void doBind(SocketAddress localAddress) throws Exception { + + } + + @Override + protected void doDisconnect() throws Exception { + + } + + @Override + protected void doClose() throws Exception { + + } + + @Override + protected void doBeginRead() throws Exception { + + } + + @Override + protected void doWrite(ChannelOutboundBuffer in) throws Exception { + + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java new file mode 100644 index 0000000000..923c410681 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.out; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public interface ProxyOutService { + + CompletableFuture processGetConsumerRunningInfo( + RemotingCommand command, + GetConsumerRunningInfoRequestHeader header + ); + + CompletableFuture processConsumeMessageDirectly( + RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header + ); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java new file mode 100644 index 0000000000..de058db13c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.route; + +import java.util.List; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.remoting.RPCHook; + +public class ClusterTopicRouteService extends TopicRouteService { + + public ClusterTopicRouteService(RPCHook rpcHook) { + super(rpcHook); + } + + @Override + public MessageQueueView getCurrentMessageQueueView(String topicName) throws Exception { + return getAllMessageQueueView(topicName); + } + + @Override + public ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, + String topicName) throws Exception { + TopicRouteData topicRouteData = getAllMessageQueueView(topicName).getTopicRouteData(); + + ProxyTopicRouteData proxyTopicRouteData = new ProxyTopicRouteData(); + proxyTopicRouteData.setQueueDatas(topicRouteData.getQueueDatas()); + + for (BrokerData brokerData : topicRouteData.getBrokerDatas()) { + ProxyTopicRouteData.ProxyBrokerData proxyBrokerData = new ProxyTopicRouteData.ProxyBrokerData(); + proxyBrokerData.setCluster(brokerData.getCluster()); + proxyBrokerData.setBrokerName(brokerData.getBrokerName()); + for (Long brokerId : brokerData.getBrokerAddrs().keySet()) { + proxyBrokerData.getBrokerAddrs().put(brokerId, requestHostAndPortList); + } + proxyTopicRouteData.getBrokerDatas().add(proxyBrokerData); + } + + return proxyTopicRouteData; + } + + @Override + public String getBrokerAddr(String brokerName) throws Exception { + List brokerDataList = getAllMessageQueueView(brokerName).getTopicRouteData().getBrokerDatas(); + if (brokerDataList.isEmpty()) { + return null; + } + return brokerDataList.get(0).getBrokerAddrs().get(MixAll.MASTER_ID); + } +} 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 new file mode 100644 index 0000000000..87d9078997 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteService.java @@ -0,0 +1,102 @@ +/* + * 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.service.route; + +import com.google.common.collect.Lists; +import com.google.common.net.HostAndPort; +import java.util.HashMap; +import java.util.List; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.BrokerConfig; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.remoting.RPCHook; + +public class LocalTopicRouteService extends TopicRouteService { + + private final BrokerController brokerController; + private final List brokerDataList; + private final int grpcPort; + + public LocalTopicRouteService(BrokerController brokerController, RPCHook rpcHook) { + super(rpcHook); + this.brokerController = brokerController; + BrokerConfig brokerConfig = this.brokerController.getBrokerConfig(); + HashMap brokerAddrs = new HashMap<>(); + brokerAddrs.put(MixAll.MASTER_ID, this.brokerController.getBrokerAddr()); + this.brokerDataList = Lists.newArrayList( + new BrokerData(brokerConfig.getBrokerClusterName(), brokerConfig.getBrokerName(), brokerAddrs) + ); + this.grpcPort = ConfigurationManager.getProxyConfig().getGrpcServerPort(); + } + + @Override + public MessageQueueView getCurrentMessageQueueView(String topic) throws Exception { + TopicConfig topicConfig = this.brokerController.getTopicConfigManager().getTopicConfigTable().get(topic); + return new MessageQueueView(topic, toTopicRouteData(topicConfig)); + } + + @Override + public ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, String topicName) throws Exception { + MessageQueueView messageQueueView = getAllMessageQueueView(topicName); + TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); + + ProxyTopicRouteData proxyTopicRouteData = new ProxyTopicRouteData(); + proxyTopicRouteData.setQueueDatas(topicRouteData.getQueueDatas()); + + for (BrokerData brokerData : topicRouteData.getBrokerDatas()) { + ProxyTopicRouteData.ProxyBrokerData proxyBrokerData = new ProxyTopicRouteData.ProxyBrokerData(); + proxyBrokerData.setCluster(brokerData.getCluster()); + proxyBrokerData.setBrokerName(brokerData.getBrokerName()); + for (Long brokerId : brokerData.getBrokerAddrs().keySet()) { + String brokerAddr = brokerData.getBrokerAddrs().get(brokerId); + HostAndPort brokerHostAndPort = HostAndPort.fromString(brokerAddr); + HostAndPort grpcHostAndPort = HostAndPort.fromParts(brokerHostAndPort.getHost(), grpcPort); + + proxyBrokerData.getBrokerAddrs().put(brokerId, Lists.newArrayList(new Address(Address.AddressScheme.IPv4, grpcHostAndPort))); + } + proxyTopicRouteData.getBrokerDatas().add(proxyBrokerData); + } + + return proxyTopicRouteData; + } + + @Override + public String getBrokerAddr(String brokerName) throws Exception { + return this.brokerController.getBrokerAddr(); + } + + protected TopicRouteData toTopicRouteData(TopicConfig topicConfig) { + TopicRouteData topicRouteData = new TopicRouteData(); + topicRouteData.setBrokerDatas(brokerDataList); + + QueueData queueData = new QueueData(); + queueData.setPerm(topicConfig.getPerm()); + queueData.setReadQueueNums(topicConfig.getReadQueueNums()); + queueData.setWriteQueueNums(topicConfig.getWriteQueueNums()); + queueData.setTopicSysFlag(topicConfig.getTopicSysFlag()); + queueData.setBrokerName(this.brokerController.getBrokerConfig().getBrokerName()); + topicRouteData.setQueueDatas(Lists.newArrayList(queueData)); + + return topicRouteData; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java index 6e40325ad7..f37155e319 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelector.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import java.util.ArrayList; import java.util.Collections; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java similarity index 85% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueWrapper.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java index 7a4a8f9788..303dfe2a77 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/MessageQueueWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/MessageQueueView.java @@ -14,18 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -public class MessageQueueWrapper { - public static final MessageQueueWrapper WRAPPED_EMPTY_QUEUE = new MessageQueueWrapper("", new TopicRouteData()); +public class MessageQueueView { + public static final MessageQueueView WRAPPED_EMPTY_QUEUE = new MessageQueueView("", new TopicRouteData()); private final MessageQueueSelector readSelector; private final MessageQueueSelector writeSelector; private final TopicRouteWrapper topicRouteWrapper; - public MessageQueueWrapper(String topic, TopicRouteData topicRouteData) { + public MessageQueueView(String topic, TopicRouteData topicRouteData) { this.topicRouteWrapper = new TopicRouteWrapper(topicRouteData, topic); this.readSelector = new MessageQueueSelector(topicRouteWrapper, true); @@ -54,7 +54,7 @@ public class MessageQueueWrapper { @Override public String toString() { - return "MessageQueueWrapper{" + + return "MessageQueueView{" + "readSelector=" + readSelector + ", writeSelector=" + writeSelector + ", topicRouteWrapper=" + topicRouteWrapper + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java new file mode 100644 index 0000000000..40bd844f4e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java @@ -0,0 +1,77 @@ +/* + * 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.service.route; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.proxy.common.Address; + +public class ProxyTopicRouteData { + + public static class ProxyBrokerData { + private String cluster; + private String brokerName; + private Map/* broker address */> brokerAddrs = new HashMap<>(); + + public String getCluster() { + return cluster; + } + + public void setCluster(String cluster) { + this.cluster = cluster; + } + + public String getBrokerName() { + return brokerName; + } + + public void setBrokerName(String brokerName) { + this.brokerName = brokerName; + } + + public Map> getBrokerAddrs() { + return brokerAddrs; + } + + public void setBrokerAddrs(Map> brokerAddrs) { + this.brokerAddrs = brokerAddrs; + } + } + + private List queueDatas = new ArrayList<>(); + private List brokerDatas = new ArrayList<>(); + + public List getQueueDatas() { + return queueDatas; + } + + public void setQueueDatas(List queueDatas) { + this.queueDatas = queueDatas; + } + + public List getBrokerDatas() { + return brokerDatas; + } + + public void setBrokerDatas( + List brokerDatas) { + this.brokerDatas = brokerDatas; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java index 78a388214d..88446c7195 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import java.util.Objects; import org.apache.rocketmq.common.message.MessageQueue; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteHelper.java similarity index 97% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteHelper.java index 97b345d703..2df41255df 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteHelper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteHelper.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import org.apache.rocketmq.client.common.ClientErrorCode; import org.apache.rocketmq.client.exception.MQBrokerException; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java similarity index 55% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java index ff6a653160..f1d3df58e0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteCache.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteService.java @@ -14,40 +14,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; -import com.google.common.hash.Hashing; +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.exception.MQClientException; -import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractCacheLoader; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.connector.DefaultForwardClient; +import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.remoting.RPCHook; -public class TopicRouteCache { +public abstract class TopicRouteService extends AbstractStartAndShutdown { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final LoadingCache topicCache; + private final LoadingCache topicCache; + + private final MQClientAPIFactory mqClientAPIFactory; + private final ScheduledExecutorService scheduledExecutorService; private final ThreadPoolExecutor cacheRefreshExecutor; - private final DefaultForwardClient defaultClient; - - public TopicRouteCache(DefaultForwardClient defaultClient) { + public TopicRouteService(RPCHook rpcHook) { ProxyConfig config = ConfigurationManager.getProxyConfig(); - this.defaultClient = defaultClient; + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("TopicRouteService_") + ); this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( config.getTopicRouteThreadPoolNums(), config.getTopicRouteThreadPoolNums(), @@ -56,55 +64,39 @@ public class TopicRouteCache { "TopicRouteCacheRefresh", config.getTopicRouteThreadPoolQueueCapacity() ); + this.mqClientAPIFactory = new MQClientAPIFactory( + "TopicRouteServiceClient_", + 1, + 1, + new DoNothingClientRemotingProcessor(null), + rpcHook, + this.scheduledExecutorService + ); this.topicCache = CacheBuilder.newBuilder() .maximumSize(config.getTopicRouteCacheMaxNum()) .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new TopicRouteCacheLoader()); + + this.init(); } - public MessageQueueWrapper getMessageQueue(String topicName) throws Exception { + protected void init() { + this.appendShutdown(this.scheduledExecutorService::shutdown); + this.appendStartAndShutdown(this.mqClientAPIFactory); + } + + public MessageQueueView getAllMessageQueueView(String topicName) throws Exception { return getCacheMessageQueueWrapper(this.topicCache, topicName); } - public String getBrokerAddr(String brokerName) throws Exception { - List brokerDataList = getMessageQueue(brokerName).getTopicRouteData().getBrokerDatas(); - if (brokerDataList.isEmpty()) { - return null; - } - return brokerDataList.get(0).getBrokerAddrs().get(MixAll.MASTER_ID); - } + public abstract MessageQueueView getCurrentMessageQueueView(String topicName) throws Exception; - public SelectableMessageQueue selectOneWriteQueue(String topic, SelectableMessageQueue last) throws Exception { - if (last == null) { - return getMessageQueue(topic).getWriteSelector().selectOne(false); - } - return getMessageQueue(topic).getWriteSelector().selectNextQueue(last); - } + public abstract ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, String topicName) throws Exception; - public SelectableMessageQueue selectOneWriteQueue(String topic, String brokerName, int queueId) throws Exception { - return getMessageQueue(topic).getWriteSelector() - .selectOne(brokerName, queueId); - } + public abstract String getBrokerAddr(String brokerName) throws Exception; - public SelectableMessageQueue selectOneWriteQueueByKey(String topic, String shardingKey) throws Exception { - List writeQueues = getMessageQueue(topic).getWriteSelector().getQueues(); - int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); - return writeQueues.get(bucket); - } - - public SelectableMessageQueue selectReadBrokerByName(String topic, String brokerName) throws Exception { - return getMessageQueue(topic).getReadSelector().getQueueByBrokerName(brokerName); - } - - public SelectableMessageQueue selectOneReadBroker(String topic, SelectableMessageQueue last) throws Exception { - if (last == null) { - return getMessageQueue(topic).getReadSelector().selectOne(true); - } - return getMessageQueue(topic).getReadSelector().selectNextQueue(last); - } - - protected static MessageQueueWrapper getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { - MessageQueueWrapper res = topicCache.get(key); + protected static MessageQueueView getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { + MessageQueueView res = topicCache.get(key); if (res.isEmptyCachedQueue()) { throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "No topic route info in name server for the topic: " + key); @@ -117,30 +109,28 @@ public class TopicRouteCache { && routeData.getBrokerDatas() != null && !routeData.getBrokerDatas().isEmpty(); } - protected abstract class AbstractTopicRouteCacheLoader extends AbstractCacheLoader { + protected abstract class AbstractTopicRouteCacheLoader extends AbstractCacheLoader { public AbstractTopicRouteCacheLoader() { super(cacheRefreshExecutor); } - protected abstract String loaderName(); - protected abstract TopicRouteData loadTopicRouteData(String topic) throws Exception; @Override - public MessageQueueWrapper getDirectly(String topic) throws Exception { + public MessageQueueView getDirectly(String topic) throws Exception { try { TopicRouteData topicRouteData = loadTopicRouteData(topic); if (isTopicRouteValid(topicRouteData)) { - MessageQueueWrapper tmp = new MessageQueueWrapper(topic, topicRouteData); - log.info("load {} from namesrv. topic: {}, queue: {}", loaderName(), topic, tmp); + MessageQueueView tmp = new MessageQueueView(topic, topicRouteData); + log.info("load topic route from namesrv. topic: {}, queue: {}", topic, tmp); return tmp; } - return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; + return MessageQueueView.WRAPPED_EMPTY_QUEUE; } catch (Exception e) { if (TopicRouteHelper.isTopicNotExistError(e)) { - return MessageQueueWrapper.WRAPPED_EMPTY_QUEUE; + return MessageQueueView.WRAPPED_EMPTY_QUEUE; } throw e; } @@ -148,20 +138,15 @@ public class TopicRouteCache { @Override protected void onErr(String key, Exception e) { - log.error("load {} from namesrv failed. topic:{}", loaderName(), key, e); + log.error("load topic route from namesrv failed. topic:{}", key, e); } } protected class TopicRouteCacheLoader extends AbstractTopicRouteCacheLoader { - @Override - protected String loaderName() { - return "topicRoute"; - } - @Override protected TopicRouteData loadTopicRouteData(String topic) throws Exception { - return defaultClient.getTopicRouteInfoFromNameServer(topic); + return mqClientAPIFactory.getClient().getTopicRouteInfoFromNameServer(topic, Duration.ofSeconds(3).toMillis()); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteWrapper.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteWrapper.java index 5b566dbc13..3950d92a1d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/route/TopicRouteWrapper.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/TopicRouteWrapper.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.route; +package org.apache.rocketmq.proxy.service.route; import java.util.HashMap; import java.util.List; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java similarity index 80% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index 92c7d63964..be5e3b0171 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionHeartbeatRegisterService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -14,10 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.transaction; +package org.apache.rocketmq.proxy.service.transaction; import com.google.common.collect.Sets; -import io.grpc.Context; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -26,9 +26,13 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; @@ -39,34 +43,47 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.mqclient.ProxyClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.remoting.RPCHook; -public class TransactionHeartbeatRegisterService implements StartAndShutdown { +public class ClusterTransactionService implements StartAndShutdown, TransactionService { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private static final String TRANS_HEARTBEAT_CLIENT_ID = "rmq-proxy-producer-client"; - private final ForwardProducer forwardProducer; - private final TopicRouteCache topicRouteCache; + private final MQClientAPIFactory mqClientAPIFactory; + private final TopicRouteService topicRouteService; + private final ScheduledExecutorService scheduledExecutorService; private ThreadPoolExecutor heartbeatExecutors; private final Map/* cluster list */> groupClusterData = new ConcurrentHashMap<>(); private TxHeartbeatServiceThread txHeartbeatServiceThread; - public TransactionHeartbeatRegisterService(ForwardProducer forwardProducer, TopicRouteCache topicRouteCache) { - this.forwardProducer = forwardProducer; - this.topicRouteCache = topicRouteCache; + public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, RPCHook rpcHook) { + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("ClusterTransactionScheduledThread_")); + this.topicRouteService = topicRouteService; + this.mqClientAPIFactory = new MQClientAPIFactory( + "ClusterTransaction_", + 1, + 1, + new ProxyClientRemotingProcessor(producerManager), + rpcHook, + scheduledExecutorService); } - public void addProducerGroup(String group, List topicList) { + @Override + public void addTransactionSubscription(String group, List topicList) { for (String topic : topicList) { - addProducerGroup(group, topic); + addTransactionSubscription(group, topic); } } - public void addProducerGroup(String group, String topic) { + @Override + public void addTransactionSubscription(String group, String topic) { try { groupClusterData.compute(group, (groupName, clusterDataSet) -> { if (clusterDataSet == null) { @@ -80,7 +97,8 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { } } - public void replaceProducerGroup(String group, List topicList) { + @Override + public void replaceTransactionSubscription(String group, List topicList) { Set clusterDataSet = new HashSet<>(); for (String topic : topicList) { clusterDataSet.addAll(getClusterDataFromTopic(topic)); @@ -90,7 +108,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { private Set getClusterDataFromTopic(String topic) { try { - MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(topic); + MessageQueueView messageQueue = this.topicRouteService.getAllMessageQueueView(topic); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); if (brokerDataList == null) { @@ -107,7 +125,8 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { return Collections.emptySet(); } - public void onProducerGroupOffline(String group) { + @Override + public void unSubscribeAllTransactionTopic(String group) { groupClusterData.remove(group); } @@ -175,8 +194,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData) { try { - Context ctx = Context.current(); - MessageQueueWrapper messageQueue = this.topicRouteCache.getMessageQueue(clusterName); + MessageQueueView messageQueue = this.topicRouteService.getAllMessageQueueView(clusterName); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); if (brokerDataList == null) { return; @@ -185,7 +203,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { heartbeatExecutors.submit(() -> { String brokerAddr = brokerData.selectBrokerAddr(); try { - this.forwardProducer.heartBeat(ctx, brokerAddr, heartbeatData); + this.mqClientAPIFactory.getClient().sendHeartbeatOneway(brokerAddr, heartbeatData, Duration.ofSeconds(3).toMillis()); } catch (Exception e) { log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, e); } @@ -247,6 +265,7 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); txHeartbeatServiceThread = new TxHeartbeatServiceThread(); + mqClientAPIFactory.start(); txHeartbeatServiceThread.start(); heartbeatExecutors = ThreadPoolMonitor.createAndMonitor( proxyConfig.getTransactionHeartbeatThreadPoolNums(), @@ -261,5 +280,6 @@ public class TransactionHeartbeatRegisterService implements StartAndShutdown { public void shutdown() throws Exception { txHeartbeatServiceThread.shutdown(); heartbeatExecutors.shutdown(); + mqClientAPIFactory.shutdown(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java new file mode 100644 index 0000000000..c465520a98 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service.transaction; + +import java.util.List; + +public class LocalTransactionService implements TransactionService { + @Override public void addTransactionSubscription(String group, List topicList) { + + } + + @Override public void addTransactionSubscription(String group, String topic) { + + } + + @Override public void replaceTransactionSubscription(String group, List topicList) { + + } + + @Override public void unSubscribeAllTransactionTopic(String group) { + + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java similarity index 79% rename from proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java index e0614c2636..3a22da078e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java @@ -14,11 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.transaction; +package org.apache.rocketmq.proxy.service.transaction; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -28,29 +25,27 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageId; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.remoting.common.RemotingUtil; public class TransactionId { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private SocketAddress brokerAddr; + private String brokerName; private String brokerTransactionId; private long commitLogOffset; private long tranStateTableOffset; private String proxyTransactionId; public TransactionId( - SocketAddress brokerAddr, + String brokerName, String brokerTransactionId, long commitLogOffset, long tranStateTableOffset, String proxyTransactionId ) { - this.brokerAddr = brokerAddr; + this.brokerName = brokerName; this.brokerTransactionId = brokerTransactionId; this.commitLogOffset = commitLogOffset; this.tranStateTableOffset = tranStateTableOffset; @@ -60,7 +55,7 @@ public class TransactionId { public TransactionId() { } - public static TransactionId genByBrokerTransactionId(String brokerAddr, SendResult sendResult) { + public static TransactionId genByBrokerTransactionId(String brokerName, SendResult sendResult) { long commitLogOffset = 0L; try { if (sendResult.getOffsetMsgId() != null) { @@ -69,14 +64,14 @@ public class TransactionId { commitLogOffset = generateCommitLogOffset(sendResult.getMsgId()); } } catch (Exception e) { - log.warn("genFromBrokerTransactionId failed. brokerAddr: {}, sendResult: {}", brokerAddr, sendResult, e); + log.warn("genFromBrokerTransactionId failed. brokerName: {}, sendResult: {}", brokerName, sendResult, e); } - return genByBrokerTransactionId(RemotingUtil.string2SocketAddress(brokerAddr), sendResult.getTransactionId(), + return genByBrokerTransactionId(brokerName, sendResult.getTransactionId(), commitLogOffset, sendResult.getQueueOffset()); } public static TransactionId genByBrokerTransactionId( - SocketAddress brokerAddr, + String brokerName, String orgTransactionId, long commitLogOffset, long tranStateTableOffset @@ -85,10 +80,12 @@ public class TransactionId { if (StringUtils.isNotBlank(orgTransactionId)) { orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); } + byte[] brokerNameByte = brokerName.getBytes(StandardCharsets.UTF_8); - ByteBuffer byteBuffer = ByteBuffer.allocate(8 + 4 + orgTransactionIdByte.length + 8 + 8); - byteBuffer.put(MessageExt.socketAddress2ByteBuffer(brokerAddr)); + ByteBuffer byteBuffer = ByteBuffer.allocate(4 + brokerNameByte.length + 4 + orgTransactionIdByte.length + 8 + 8); + byteBuffer.putInt(brokerNameByte.length); + byteBuffer.put(brokerNameByte); byteBuffer.putInt(orgTransactionIdByte.length); byteBuffer.put(orgTransactionIdByte); byteBuffer.putLong(commitLogOffset); @@ -97,7 +94,7 @@ public class TransactionId { String gatewayTransactionId = UtilAll.bytes2string(byteBuffer.array()); return TransactionId.builder() - .brokerAddr(brokerAddr) + .brokerName(brokerName) .brokerTransactionId(orgTransactionId) .commitLogOffset(commitLogOffset) .tranStateTableOffset(tranStateTableOffset) @@ -108,10 +105,9 @@ public class TransactionId { public static TransactionId decode(String transactionId) throws UnknownHostException { ByteBuffer byteBuffer = ByteBuffer.wrap(UtilAll.string2bytes(transactionId)); - byte[] ip = new byte[4]; - byteBuffer.get(ip); - int port = byteBuffer.getInt(); - SocketAddress brokerAddr = new InetSocketAddress(InetAddress.getByAddress(ip), port); + int brokerNameLen = byteBuffer.getInt(); + byte[] brokerNameByte = new byte[brokerNameLen]; + byteBuffer.get(brokerNameByte); int orgTransactionIdLen = byteBuffer.getInt(); byte[] orgTransactionIdByte = new byte[0]; @@ -124,7 +120,7 @@ public class TransactionId { long tranStateTableOffset = byteBuffer.getLong(); return TransactionId.builder() - .brokerAddr(brokerAddr) + .brokerName(new String(brokerNameByte, StandardCharsets.UTF_8)) .brokerTransactionId(new String(orgTransactionIdByte, StandardCharsets.UTF_8)) .commitLogOffset(commitLogOffset) .tranStateTableOffset(tranStateTableOffset) @@ -150,54 +146,56 @@ public class TransactionId { return false; } TransactionId id = (TransactionId) o; - return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && Objects.equals(brokerAddr, id.brokerAddr) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && Objects.equals(proxyTransactionId, id.proxyTransactionId); + return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && + Objects.equals(brokerName, id.brokerName) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && + Objects.equals(proxyTransactionId, id.proxyTransactionId); } @Override public int hashCode() { - return Objects.hash(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); + return Objects.hash(brokerName, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); } public static TransactionIdBuilder builder() { return new TransactionIdBuilder(); } - public SocketAddress getBrokerAddr() { - return this.brokerAddr; + public String getBrokerName() { + return brokerName; + } + + public void setBrokerName(String brokerName) { + this.brokerName = brokerName; } public String getBrokerTransactionId() { - return this.brokerTransactionId; - } - - public long getCommitLogOffset() { - return this.commitLogOffset; - } - - public long getTranStateTableOffset() { - return this.tranStateTableOffset; - } - - public String getProxyTransactionId() { - return this.proxyTransactionId; - } - - public void setBrokerAddr(SocketAddress brokerAddr) { - this.brokerAddr = brokerAddr; + return brokerTransactionId; } public void setBrokerTransactionId(String brokerTransactionId) { this.brokerTransactionId = brokerTransactionId; } + public long getCommitLogOffset() { + return commitLogOffset; + } + public void setCommitLogOffset(long commitLogOffset) { this.commitLogOffset = commitLogOffset; } + public long getTranStateTableOffset() { + return tranStateTableOffset; + } + public void setTranStateTableOffset(long tranStateTableOffset) { this.tranStateTableOffset = tranStateTableOffset; } + public String getProxyTransactionId() { + return proxyTransactionId; + } + public void setProxyTransactionId(String proxyTransactionId) { this.proxyTransactionId = proxyTransactionId; } @@ -205,7 +203,7 @@ public class TransactionId { @Override public String toString() { return "TransactionId{" + - "brokerAddr=" + brokerAddr + + "brokerName=" + brokerName + ", brokerTransactionId='" + brokerTransactionId + '\'' + ", commitLogOffset=" + commitLogOffset + ", tranStateTableOffset=" + tranStateTableOffset + @@ -214,7 +212,7 @@ public class TransactionId { } public static class TransactionIdBuilder { - private SocketAddress brokerAddr; + private String brokerName; private String brokerTransactionId; private long commitLogOffset; private long tranStateTableOffset; @@ -223,8 +221,8 @@ public class TransactionId { TransactionIdBuilder() { } - public TransactionIdBuilder brokerAddr(SocketAddress brokerAddr) { - this.brokerAddr = brokerAddr; + public TransactionIdBuilder brokerName(String brokerName) { + this.brokerName = brokerName; return this; } @@ -249,13 +247,13 @@ public class TransactionId { } public TransactionId build() { - return new TransactionId(brokerAddr, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); + return new TransactionId(brokerName, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); } @Override public String toString() { return "TransactionId.TransactionIdBuilder{" + - "brokerAddr=" + brokerAddr + + "brokerName=" + brokerName + ", brokerTransactionId='" + brokerTransactionId + '\'' + ", commitLogOffset=" + commitLogOffset + ", tranStateTableOffset=" + tranStateTableOffset + diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java similarity index 69% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java index 398dc5d790..75b83e98ac 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/service/ReceiveMessageResultFilter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java @@ -14,16 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.rocketmq.proxy.service.transaction; -package org.apache.rocketmq.proxy.grpc.v2.service; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; import java.util.List; -import org.apache.rocketmq.common.message.MessageExt; -public interface ReceiveMessageResultFilter { +public interface TransactionService { - List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList); + void addTransactionSubscription(String group, List topicList); + + void addTransactionSubscription(String group, String topic); + + void replaceTransactionSubscription(String group, List topicList); + + void unSubscribeAllTransactionTopic(String group); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java index 9d3b572bf8..ca36f5f20f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.proxy.config; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyMode; +import org.apache.rocketmq.proxy.ProxyMode; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java deleted file mode 100644 index 2cb06da6ab..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ /dev/null @@ -1,142 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.FilterType; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.Publishing; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; -import apache.rocketmq.v2.SubscriptionEntry; -import io.grpc.Context; -import io.netty.channel.Channel; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import org.apache.rocketmq.broker.client.ClientChannelInfo; -import org.apache.rocketmq.broker.client.ConsumerGroupInfo; -import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; -import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.remoting.protocol.LanguageCode; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - -public class ForwardClientServiceTest extends BaseServiceTest { - - private ChannelManager channelManager = new ChannelManager(); - private TelemetryCommandManager telemetryCommandManager = new TelemetryCommandManager(); - private ForwardClientService clientService; - - @Override - public void beforeEach() throws Throwable { - clientService = new ForwardClientService( - this.connectorManager, - Executors.newSingleThreadScheduledExecutor(), - this.channelManager, - this.grpcClientManager, - this.telemetryCommandManager); - clientService.start(); - } - - @Test - public void testProducerHeartbeat() { - Settings clientSettings = Settings.newBuilder() - .setClientType(ClientType.PRODUCER) - .setPublishing(Publishing.newBuilder() - .addTopics(Resource.newBuilder() - .setName("topic1") - .build()) - .addTopics(Resource.newBuilder() - .setName("topic2") - .build()) - .build()) - .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); - - clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); - - assertEquals(2, clientService.getProducerManager().getGroupChannelTable().size()); - Channel channel = clientService.getProducerManager().findChannel(CLIENT_ID); - assertNotNull(channel); - assertTrue(channel instanceof GrpcClientChannel); - - clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder().build()); - assertTrue(clientService.getProducerManager().getGroupChannelTable().isEmpty()); - } - - @Test - public void testConsumerHeartbeat() { - List subscriptionEntryList = new ArrayList<>(); - subscriptionEntryList.add(SubscriptionEntry.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setExpression(FilterExpression.newBuilder() - .setExpression("*") - .setType(FilterType.TAG) - .build()) - .build()); - - Settings clientSettings = Settings.newBuilder() - .setClientType(ClientType.PUSH_CONSUMER) - .setSubscription(Subscription.newBuilder() - .addAllSubscriptions(subscriptionEntryList) - .build()) - .build(); - when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); - - clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("consumerGroup") - .build()) - .build()); - - ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", CLIENT_ID); - assertNotNull(clientChannelInfo); - assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); - assertEquals(CLIENT_ID, clientChannelInfo.getClientId()); - assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); - ConsumerGroupInfo consumerGroupInfo = clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup"); - assertEquals(MessageModel.CLUSTERING, consumerGroupInfo.getMessageModel()); - assertEquals(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, consumerGroupInfo.getConsumeFromWhere()); - assertEquals(ConsumeType.CONSUME_PASSIVELY, consumerGroupInfo.getConsumeType()); - assertEquals("TAG", consumerGroupInfo.getSubscriptionTable().get("topic").getExpressionType()); - assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); - - - clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("consumerGroup") - .build()) - .build()); - assertNull(clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup")); - } -} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java deleted file mode 100644 index eafc3a4325..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ /dev/null @@ -1,105 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateCheckRequest; -import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -import org.apache.rocketmq.remoting.common.RemotingHelper; -import org.assertj.core.util.Lists; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class TransactionServiceTest extends BaseServiceTest { - - private TransactionService transactionService; - @Mock - private ChannelManager channelManager; - - @Override - public void beforeEach() throws Throwable { - transactionService = new TransactionService(this.connectorManager, this.channelManager); - } - - @Test - public void testCheckTransactionState() { - GrpcClientChannel channel = mock(GrpcClientChannel.class); - - when(channelManager.getClientIdList(anyString())).thenReturn(Lists.newArrayList("clientId")); - when(channelManager.getChannel(anyString(), any())).thenReturn(channel); - ArgumentCaptor flushDataCaptor = ArgumentCaptor.forClass(Object.class); - when(channel.writeAndFlush(flushDataCaptor.capture())).thenReturn(null); - - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingHelper.string2SocketAddress("127.0.0.1:8080"), - "71F99B78B6E261357FA259CCA6456118", 1234, 5678); - transactionService.checkTransactionState(new TransactionStateCheckRequest( - "group", - 1L, - 2L, - "msgId", - transactionId, - "brokerName", - createMessageExt("msgId", "msgId") - )); - - Object flushData = flushDataCaptor.getValue(); - assertTrue(flushData instanceof TelemetryCommand); - TelemetryCommand response = (TelemetryCommand) flushData; - RecoverOrphanedTransactionCommand command = response.getRecoverOrphanedTransactionCommand(); - assertEquals(transactionId.getProxyTransactionId(), command.getTransactionId()); - assertEquals("brokerName", command.getMessageQueue().getBroker().getName()); - } - - @Test - public void testEndTransaction() throws Exception { - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingHelper.string2SocketAddress("127.0.0.1:8080"), - "71F99B78B6E261357FA259CCA6456118", 1234, 5678); - ArgumentCaptor brokerAddrCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor headerCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); - doNothing().when(producerClient) - .endTransaction(any(), brokerAddrCaptor.capture(), headerCaptor.capture()); - - EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() - .setTransactionId(transactionId.getProxyTransactionId()) - .build() - ).get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(transactionId.getBrokerTransactionId(), headerCaptor.getValue().getTransactionId()); - assertEquals("127.0.0.1:8080", brokerAddrCaptor.getValue()); - } -} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java deleted file mode 100644 index a560673503..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java +++ /dev/null @@ -1,170 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import io.grpc.Context; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.ServerCallStreamObserver; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; -import org.apache.rocketmq.client.consumer.PopStatus; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(MockitoJUnitRunner.class) -public class LocalReceiveMessageResponseStreamWriterTest { - @Mock - private ServerCallStreamObserver streamObserverMock; - @Mock - private ChannelManager channelManagerMock; - @Mock - private BrokerController brokerControllerMock; - @Mock - private ReceiveMessageResultFilter receiveMessageResultFilterMock; - @Mock - private ChangeInvisibleTimeProcessor changeInvisibleTimeProcessorMock; - - private LocalReceiveMessageResponseStreamWriter localReceiveMessageResponseStreamWriter; - - @Before - public void setup() { - Mockito.when(receiveMessageResultFilterMock.filterMessage(Mockito.any(), Mockito.any(), Mockito.anyList())).thenAnswer((Answer>) invocation -> { - List messageList = new ArrayList<>(); - List messageExtList = invocation.getArgument(2); - for (MessageExt messageExt : messageExtList) { - messageList.add(GrpcConverter.buildMessage(messageExt)); - } - return messageList; - }); - localReceiveMessageResponseStreamWriter - = new LocalReceiveMessageResponseStreamWriter(streamObserverMock, null, channelManagerMock, brokerControllerMock, receiveMessageResultFilterMock); - } - - @Test - public void testWrite() { - MessageExt messageExt = new MessageExt(); - messageExt.setTopic("topic"); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); - messageExt.putUserProperty("key", "value"); - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("0") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()); - messageExt.putUserProperty("key", "value"); - List messageExtList = new ArrayList<>(); - messageExtList.add(messageExt); - localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); - ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); - Mockito.verify(streamObserverMock, Mockito.times(2)).onNext(argument.capture()); - assertThat(argument.getAllValues().get(0)).isEqualTo(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build()); - assertThat(argument.getAllValues().get(1)).isEqualTo(ReceiveMessageResponse.newBuilder() - .setMessage(GrpcConverter.buildMessage(messageExt)).build()); - } - - @Test - public void testWriteWhenNoMessage() { - localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, new ArrayList<>()); - Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")).build())); - } - - @Test - public void testWriteWhenCancel() throws RemotingCommandException { - AtomicInteger onNextCallTimes = new AtomicInteger(0); - Mockito.doAnswer(mock -> { - if (onNextCallTimes.get() <=0) { - onNextCallTimes.incrementAndGet(); - return null; - } - throw new StatusRuntimeException(Status.CANCELLED); - }).when(streamObserverMock).onNext(Mockito.any()); - Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); - MessageExt messageExt = new MessageExt(); - messageExt.setTopic("topic"); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); - messageExt.putUserProperty("key", "value"); - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("0") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()); - messageExt.putUserProperty("key", "value"); - List messageExtList = new ArrayList<>(); - messageExtList.add(messageExt); - localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); - Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build())); - Mockito.verify(changeInvisibleTimeProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.any()); - } - - @Test - public void testWriteError() { - String info = "error"; - localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), new ProxyException(Code.ILLEGAL_MESSAGE, info)); - Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_MESSAGE, info)).build())); - } -} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java deleted file mode 100644 index 20dbce41a7..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalReceiveMessageResultFilterTest.java +++ /dev/null @@ -1,135 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.Settings; -import io.grpc.Context; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.broker.processor.AckMessageProcessor; -import org.apache.rocketmq.broker.processor.SendMessageProcessor; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.proxy.channel.ChannelManager; -import org.apache.rocketmq.proxy.channel.SimpleChannel; -import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class LocalReceiveMessageResultFilterTest extends InitConfigAndLoggerTest { - @Mock - private ChannelManager channelManagerMock; - @Mock - private BrokerController brokerControllerMock; - @Mock - private GrpcClientManager grpcClientManagerMock; - @Mock - private AckMessageProcessor ackMessageProcessorMock; - @Mock - private SendMessageProcessor sendMessageProcessorMock; - - private String topic = "topic"; - - @Test - public void testFilterMessageWhenNotMatch() throws RemotingCommandException { - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); - Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); - Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); - Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); - Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); - List messageExtList = new ArrayList<>(); - MessageExt messageExt = new MessageExt(); - messageExt.setTopic(topic); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); - messageExt.putUserProperty("key", "value"); - messageExt.setTags("b"); - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("0") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()); - messageExtList.add(messageExt); - LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); - localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() - .setFilterExpression(FilterExpression.newBuilder() - .setExpression("a").build()).build(), messageExtList); - Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); - } - - @Test - public void testFilterMessageWhenDLQ() throws RemotingCommandException { - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); - Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); - Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); - Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); - Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); - Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); - List messageExtList = new ArrayList<>(); - MessageExt messageExt = new MessageExt(); - messageExt.setTopic(topic); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); - messageExt.putUserProperty("key", "value"); - messageExt.setTags("a"); - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("0") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()); - messageExtList.add(messageExt); - LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); - localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() - .setFilterExpression(FilterExpression.newBuilder() - .setExpression("a").build()).build(), messageExtList); - Mockito.verify(sendMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK)); - Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); - } -} \ No newline at end of file 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 new file mode 100644 index 0000000000..152b66c82a --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/BaseProcessorTest.java @@ -0,0 +1,103 @@ +/* + * 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 io.netty.util.internal.MathUtil; +import java.nio.charset.StandardCharsets; +import java.util.Random; +import java.util.UUID; +import org.apache.rocketmq.broker.client.ConsumerManager; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.service.message.MessageService; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.when; + +@Ignore +@RunWith(MockitoJUnitRunner.Silent.class) +public class BaseProcessorTest extends InitConfigAndLoggerTest { + protected static final Random RANDOM = new Random(); + + @Mock + protected MessagingProcessor messagingProcessor; + @Mock + protected ServiceManager serviceManager; + @Mock + protected MessageService messageService; + @Mock + protected TopicRouteService topicRouteService; + @Mock + protected ProducerManager producerManager; + @Mock + protected ConsumerManager consumerManager; + @Mock + protected TransactionService transactionService; + @Mock + protected ProxyOutService proxyOutService; + @Mock + protected ProducerProcessor producerProcessor; + @Mock + protected ConsumerProcessor consumerProcessor; + @Mock + protected TransactionProcessor transactionProcessor; + @Mock + protected ClientProcessor clientProcessor; + + public void before() throws Throwable { + super.before(); + when(serviceManager.getMessageService()).thenReturn(messageService); + when(serviceManager.getTopicRouteService()).thenReturn(topicRouteService); + when(serviceManager.getProducerManager()).thenReturn(producerManager); + when(serviceManager.getConsumerManager()).thenReturn(consumerManager); + when(serviceManager.getTransactionService()).thenReturn(transactionService); + when(serviceManager.getProxyOutService()).thenReturn(proxyOutService); + } + + protected static ProxyContext createContext() { + return ProxyContext.create(); + } + + protected static MessageExt createMessageExt(String topic, String tags, int reconsumeTimes, long invisibleTime) { + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setTags(tags); + messageExt.setReconsumeTimes(reconsumeTimes); + messageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + messageExt.setMsgId(MessageClientIDSetter.createUniqID()); + messageExt.setCommitLogOffset(RANDOM.nextInt()); + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_POP_CK, + ExtraInfoUtil.buildExtraInfo(RANDOM.nextInt(), System.currentTimeMillis(), invisibleTime, + RANDOM.nextInt(), topic, "mockBroker", RANDOM.nextInt(), RANDOM.nextInt())); + 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 new file mode 100644 index 0000000000..f2547a8b78 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ConsumerProcessorTest.java @@ -0,0 +1,174 @@ +/* + * 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 java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.KeyBuilder; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.ConsumeInitMode; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.filter.ExpressionType; +import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ConsumerProcessorTest extends BaseProcessorTest { + + private static final String CONSUMER_GROUP = "consumerGroup"; + private static final String TOPIC = "topic"; + + private ConsumerProcessor consumerProcessor; + + @Before + public void before() throws Throwable { + super.before(); + this.consumerProcessor = new ConsumerProcessor(this.messagingProcessor, this.serviceManager); + } + + @Test + public void testPopMessage() throws Throwable { + final String tag = "tag"; + final long invisibleTime = Duration.ofSeconds(15).toMillis(); + ArgumentCaptor messageQueueArgumentCaptor = ArgumentCaptor.forClass(SelectableMessageQueue.class); + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(PopMessageRequestHeader.class); + + List messageExtList = new ArrayList<>(); + messageExtList.add(createMessageExt(TOPIC, "noMatch", 0, invisibleTime)); + messageExtList.add(createMessageExt(TOPIC, tag, 0, invisibleTime)); + messageExtList.add(createMessageExt(TOPIC, tag, 1, invisibleTime)); + PopResult innerPopResult = new PopResult(PopStatus.FOUND, messageExtList); + when(this.messageService.popMessage(any(), messageQueueArgumentCaptor.capture(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(innerPopResult)); + + when(this.topicRouteService.getCurrentMessageQueueView(anyString())) + .thenReturn(mock(MessageQueueView.class)); + + ArgumentCaptor ackMessageIdArgumentCaptor = ArgumentCaptor.forClass(String.class); + when(this.messagingProcessor.ackMessage(any(), any(), ackMessageIdArgumentCaptor.capture(), anyString(), anyString(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(mock(AckResult.class))); + + ArgumentCaptor toDLQMessageIdArgumentCaptor = ArgumentCaptor.forClass(String.class); + when(this.messagingProcessor.forwardMessageToDeadLetterQueue(any(), any(), toDLQMessageIdArgumentCaptor.capture(), anyString(), anyString(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(mock(RemotingCommand.class))); + + SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + PopResult popResult = this.consumerProcessor.popMessage( + createContext(), + (ctx, messageQueueView) -> messageQueue, + CONSUMER_GROUP, + TOPIC, + 60, + invisibleTime, + Duration.ofSeconds(3).toMillis(), + ConsumeInitMode.MAX, + FilterAPI.build(TOPIC, tag, ExpressionType.TAG), + false, + (ctx, consumerGroup, subscriptionData, messageExt) -> { + if (!messageExt.getTags().equals(tag)) { + return PopMessageResultFilter.FilterResult.NO_MATCH; + } + if (messageExt.getReconsumeTimes() > 0) { + return PopMessageResultFilter.FilterResult.TO_DLQ; + } + return PopMessageResultFilter.FilterResult.MATCH; + }, + Duration.ofSeconds(3).toMillis() + ).get(); + + assertSame(messageQueue, messageQueueArgumentCaptor.getValue()); + assertEquals(CONSUMER_GROUP, requestHeaderArgumentCaptor.getValue().getConsumerGroup()); + assertEquals(TOPIC, requestHeaderArgumentCaptor.getValue().getTopic()); + assertEquals(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, requestHeaderArgumentCaptor.getValue().getMaxMsgNums()); + assertEquals(tag, requestHeaderArgumentCaptor.getValue().getExp()); + assertEquals(ExpressionType.TAG, requestHeaderArgumentCaptor.getValue().getExpType()); + + assertEquals(PopStatus.FOUND, popResult.getPopStatus()); + assertEquals(1, popResult.getMsgFoundList().size()); + assertEquals(messageExtList.get(1), popResult.getMsgFoundList().get(0)); + + assertEquals(messageExtList.get(0).getMsgId(), ackMessageIdArgumentCaptor.getValue()); + assertEquals(messageExtList.get(2).getMsgId(), toDLQMessageIdArgumentCaptor.getValue()); + } + + @Test + public void testAckMessage() throws Throwable { + ReceiptHandle handle = ReceiptHandle.create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); + assertNotNull(handle); + + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(AckMessageRequestHeader.class); + AckResult innerAckResult = new AckResult(); + innerAckResult.setStatus(AckStatus.OK); + when(this.messageService.ackMessage(any(), any(), anyString(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(innerAckResult)); + + AckResult ackResult = this.consumerProcessor.ackMessage(createContext(), handle, MessageClientIDSetter.createUniqID(), + CONSUMER_GROUP, TOPIC, 3000).get(); + + assertEquals(AckStatus.OK, ackResult.getStatus()); + assertEquals(KeyBuilder.buildPopRetryTopic(TOPIC, CONSUMER_GROUP), requestHeaderArgumentCaptor.getValue().getTopic()); + assertEquals(CONSUMER_GROUP, requestHeaderArgumentCaptor.getValue().getConsumerGroup()); + assertEquals(handle.getReceiptHandle(), requestHeaderArgumentCaptor.getValue().getExtraInfo()); + } + + @Test + public void testChangeInvisibleTime() throws Throwable { + ReceiptHandle handle = ReceiptHandle.create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); + assertNotNull(handle); + + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); + AckResult innerAckResult = new AckResult(); + innerAckResult.setStatus(AckStatus.OK); + when(this.messageService.changeInvisibleTime(any(), any(), anyString(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(innerAckResult)); + + AckResult ackResult = this.consumerProcessor.changeInvisibleTime(createContext(), handle, MessageClientIDSetter.createUniqID(), + CONSUMER_GROUP, TOPIC, 1000, 3000).get(); + + assertEquals(AckStatus.OK, ackResult.getStatus()); + assertEquals(KeyBuilder.buildPopRetryTopic(TOPIC, CONSUMER_GROUP), requestHeaderArgumentCaptor.getValue().getTopic()); + assertEquals(CONSUMER_GROUP, requestHeaderArgumentCaptor.getValue().getConsumerGroup()); + assertEquals(1000, requestHeaderArgumentCaptor.getValue().getInvisibleTime().longValue()); + assertEquals(handle.getReceiptHandle(), requestHeaderArgumentCaptor.getValue().getExtraInfo()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java new file mode 100644 index 0000000000..6d4e45c6ce --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -0,0 +1,24 @@ +/* + * 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 static org.junit.Assert.*; + +public class ProducerProcessorTest extends BaseProcessorTest { + +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java similarity index 81% rename from proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java rename to proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java index 8636cf5954..9e1887918a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/transaction/TransactionIdTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java @@ -14,26 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.connector.transaction; +package org.apache.rocketmq.proxy.service.transaction; import java.net.UnknownHostException; -import org.apache.rocketmq.remoting.common.RemotingHelper; import org.junit.Test; import static org.junit.Assert.assertEquals; public class TransactionIdTest { + private static final String BROKER_NAME = "brokerName"; + @Test public void test() throws UnknownHostException { TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + BROKER_NAME, "71F99B78B6E261357FA259CCA6456118", 1234, 5678); TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); } @@ -41,13 +42,13 @@ public class TransactionIdTest { @Test public void testEmptyTransactionId() throws UnknownHostException { TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + BROKER_NAME, "", 1234, 5678); TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); } @@ -55,13 +56,13 @@ public class TransactionIdTest { @Test public void testNullTransactionId() throws UnknownHostException { TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingHelper.string2SocketAddress("127.0.0.1:8080"), + BROKER_NAME, null, 1234, 5678); TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); assertEquals("", decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerAddr().toString(), decodeTransactionId.getBrokerAddr().toString()); + assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); } diff --git a/proxy/src/test/resources/backup/channel/InvocationChannel.java b/proxy/src/test/resources/backup/channel/InvocationChannel.java new file mode 100644 index 0000000000..4d537f740b --- /dev/null +++ b/proxy/src/test/resources/backup/channel/InvocationChannel.java @@ -0,0 +1,83 @@ +///* +// * 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.channel; +// +//import io.grpc.Context; +//import io.netty.channel.ChannelFuture; +//import java.util.Iterator; +//import java.util.Map; +//import java.util.concurrent.ConcurrentHashMap; +//import java.util.concurrent.ConcurrentMap; +//import org.apache.rocketmq.proxy.common.Cleaner; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ResponseHandler; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +// +//public abstract class InvocationChannel extends SimpleChannel implements Cleaner { +// protected final ConcurrentMap> inFlightRequestMap; +// protected final ResponseHandler handler; +// +// public InvocationChannel(Context ctx, ResponseHandler handler) { +// super(ChannelManager.createSimpleChannelDirectly(ctx)); +// this.inFlightRequestMap = new ConcurrentHashMap<>(); +// this.handler = handler; +// } +// +// @Override +// public ChannelFuture writeAndFlush(Object msg) { +// if (msg instanceof RemotingCommand) { +// RemotingCommand responseCommand = (RemotingCommand) msg; +// InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); +// if (null != context) { +// handler.handle(responseCommand, context); +// } +// inFlightRequestMap.remove(responseCommand.getOpaque()); +// } +// return super.writeAndFlush(msg); +// } +// +// @Override +// public boolean isWritable() { +// return inFlightRequestMap.size() > 0; +// } +// +// public void registerInvocationContext(int opaque, InvocationContext context) { +// inFlightRequestMap.put(opaque, context); +// } +// +// public void eraseInvocationContext(int opaque) { +// inFlightRequestMap.remove(opaque); +// } +// +// @Override +// public void clean() { +// Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); +// int count = 0; +// while (iterator.hasNext()) { +// Map.Entry> entry = iterator.next(); +// if (entry.getValue().expired(expiredTimeSec)) { +// iterator.remove(); +// count++; +// log.debug("An expired request is found, created time-point: {}, Request: {}", +// entry.getValue().getTimestamp(), entry.getValue().getRequest()); +// } +// } +// if (count > 0) { +// log.warn("[BUG] {} expired in-flight requests is cleaned.", count); +// } +// } +//} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationContext.java b/proxy/src/test/resources/backup/channel/InvocationContext.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/channel/InvocationContext.java rename to proxy/src/test/resources/backup/channel/InvocationContext.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java b/proxy/src/test/resources/backup/channel/SimpleChannel.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java rename to proxy/src/test/resources/backup/channel/SimpleChannel.java index cd3a5a9bed..da9c7fb47e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannel.java +++ b/proxy/src/test/resources/backup/channel/SimpleChannel.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.channel; +package backup.channel; import com.google.common.base.Strings; import io.netty.channel.AbstractChannel; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java b/proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java similarity index 99% rename from proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java rename to proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java index a78c5727f7..1811996a94 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/channel/SimpleChannelHandlerContext.java +++ b/proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.channel; +package backup.channel; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.Channel; diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java b/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java new file mode 100644 index 0000000000..e21753dcd2 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java @@ -0,0 +1,733 @@ +///* +// * 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.grpc.v2.common; +// +//import apache.rocketmq.v2.AckMessageRequest; +//import apache.rocketmq.v2.Broker; +//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +//import apache.rocketmq.v2.ClientType; +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Digest; +//import apache.rocketmq.v2.DigestType; +//import apache.rocketmq.v2.Encoding; +//import apache.rocketmq.v2.EndTransactionRequest; +//import apache.rocketmq.v2.FilterExpression; +//import apache.rocketmq.v2.FilterType; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +//import apache.rocketmq.v2.HeartbeatRequest; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.MessageQueue; +//import apache.rocketmq.v2.MessageType; +//import apache.rocketmq.v2.NotifyClientTerminationRequest; +//import apache.rocketmq.v2.Permission; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.SendMessageRequest; +//import apache.rocketmq.v2.Settings; +//import apache.rocketmq.v2.SubscriptionEntry; +//import apache.rocketmq.v2.SystemProperties; +//import apache.rocketmq.v2.TransactionResolution; +//import apache.rocketmq.v2.TransactionSource; +//import apache.rocketmq.v2.VerifyMessageResult; +//import com.google.common.collect.Maps; +//import com.google.protobuf.ByteString; +//import com.google.protobuf.Duration; +//import com.google.protobuf.Timestamp; +//import com.google.protobuf.util.Durations; +//import com.google.protobuf.util.Timestamps; +//import io.grpc.Context; +//import java.net.SocketAddress; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.HashMap; +//import java.util.HashSet; +//import java.util.List; +//import java.util.Map; +//import java.util.Set; +//import java.util.concurrent.TimeUnit; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.common.constant.ConsumeInitMode; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.constant.PermName; +//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.filter.ExpressionType; +//import org.apache.rocketmq.common.filter.FilterAPI; +//import org.apache.rocketmq.common.message.MessageAccessor; +//import org.apache.rocketmq.common.message.MessageConst; +//import org.apache.rocketmq.common.message.MessageDecoder; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.NamespaceUtil; +//import org.apache.rocketmq.common.protocol.body.CMResult; +//import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; +//import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +//import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +//import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +//import org.apache.rocketmq.common.protocol.route.QueueData; +//import org.apache.rocketmq.common.sysflag.MessageSysFlag; +//import org.apache.rocketmq.common.utils.BinaryUtil; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +//import org.apache.rocketmq.proxy.config.ConfigurationManager; +//import org.apache.rocketmq.proxy.service.transaction.TransactionId; +// +//public class GrpcConverter { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// public static String wrapResourceWithNamespace(Resource resource) { +// return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); +// } +// +// public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, +// Settings clientSettings) { +// HeartbeatData heartbeatData = new HeartbeatData(); +// heartbeatData.setClientID(clientId); +// switch (clientSettings.getClientType()) { +// case PRODUCER: { +// Set producerDataSet = new HashSet<>(); +// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { +// String topicName = wrapResourceWithNamespace(topic); +// producerDataSet.add(buildProducerData(topicName)); +// } +// heartbeatData.setProducerDataSet(producerDataSet); +// break; +// } +// case PUSH_CONSUMER: +// case SIMPLE_CONSUMER: { +// String groupName = wrapResourceWithNamespace(request.getGroup()); +// Set consumerDataSet = new HashSet<>(); +// consumerDataSet.add(buildConsumerData(groupName, clientSettings)); +// heartbeatData.setConsumerDataSet(consumerDataSet); +// break; +// } +// } +// return heartbeatData; +// } +// +// public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(String groupName) { +// org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData +// = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); +// buildProducerData.setGroupName(groupName); +// return buildProducerData; +// } +// +// public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, +// Settings clientSettings) { +// org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); +// buildConsumerData.setGroupName(groupName); +// buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); +// +// buildConsumerData.setMessageModel(MessageModel.CLUSTERING); +// buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); +// Set subscriptionDataSet = +// buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()); +// buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); +// return buildConsumerData; +// } +// +// public static ConsumeType buildConsumeType(ClientType clientType) { +// switch (clientType) { +// case SIMPLE_CONSUMER: +// return ConsumeType.CONSUME_ACTIVELY; +// case PUSH_CONSUMER: +// return ConsumeType.CONSUME_PASSIVELY; +// default: +// throw new IllegalArgumentException("Client type is not consumer, type: " + clientType); +// } +// } +// +// public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, +// String producerGroup, int queueId) { +// SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); +// +// if (request.getMessagesCount() <= 0) { +// throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); +// } +// if (request.getMessagesCount() > 1) { +// requestHeader.setBatch(true); +// } +// Message message = request.getMessages(0); +// SystemProperties systemProperties = message.getSystemProperties(); +// +// Map property = buildMessageProperty(message, producerGroup); +// requestHeader.setProducerGroup(producerGroup); +// requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); +// requestHeader.setDefaultTopic(""); +// requestHeader.setDefaultTopicQueueNums(0); +// requestHeader.setQueueId(queueId); +// // sysFlag (body encoding & message type) +// int sysFlag = 0; +// Encoding bodyEncoding = systemProperties.getBodyEncoding(); +// if (bodyEncoding.equals(Encoding.GZIP)) { +// sysFlag |= MessageSysFlag.COMPRESSED_FLAG; +// } +// // transaction +// MessageType messageType = systemProperties.getMessageType(); +// if (messageType.equals(MessageType.TRANSACTION)) { +// sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; +// } +// requestHeader.setSysFlag(sysFlag); +// requestHeader.setBornTimestamp(Timestamps.toMillis(systemProperties.getBornTimestamp())); +// requestHeader.setFlag(0); +// requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); +// requestHeader.setReconsumeTimes(systemProperties.getDeliveryAttempt()); +// +// return requestHeader; +// } +// +// public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime, boolean isFifo) { +// Resource group = request.getGroup(); +// String groupName = GrpcConverter.wrapResourceWithNamespace(group); +// MessageQueue messageQueue = request.getMessageQueue(); +// Resource topic = messageQueue.getTopic(); +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// int queueId = messageQueue.getId(); +// int maxMessageNumbers = request.getBatchSize(); +// if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { +// log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", +// maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); +// maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; +// } +// long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); +// long bornTime = System.currentTimeMillis(); +// +// FilterExpression filterExpression = request.getFilterExpression(); +// String expression = filterExpression.getExpression(); +// String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); +// +// PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); +// requestHeader.setConsumerGroup(groupName); +// requestHeader.setTopic(topicName); +// requestHeader.setQueueId(queueId); +// requestHeader.setMaxMsgNums(maxMessageNumbers); +// requestHeader.setInvisibleTime(invisibleTime); +// requestHeader.setPollTime(pollTime); +// requestHeader.setBornTime(bornTime); +// requestHeader.setInitMode(ConsumeInitMode.MAX); +// requestHeader.setExpType(expressionType); +// requestHeader.setExp(expression); +// requestHeader.setOrder(isFifo); +// +// return requestHeader; +// } +// +// public static AckMessageRequestHeader buildAckMessageRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { +// return buildAckMessageRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle); +// } +// +// public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { +// return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); +// } +// +// public static AckMessageRequestHeader buildAckMessageRequestHeader(Resource topic, Resource group, ReceiptHandle handle) { +// String groupName = GrpcConverter.wrapResourceWithNamespace(group); +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// +// AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); +// ackMessageRequestHeader.setConsumerGroup(groupName); +// ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); +// ackMessageRequestHeader.setQueueId(handle.getQueueId()); +// ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); +// ackMessageRequestHeader.setOffset(handle.getOffset()); +// return ackMessageRequestHeader; +// } +// +// public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { +// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); +// +// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); +// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); +// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); +// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); +// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); +// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); +// changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); +// return changeInvisibleTimeRequestHeader; +// } +// +// public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { +// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); +// +// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); +// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); +// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); +// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); +// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); +// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); +// changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); +// return changeInvisibleTimeRequestHeader; +// } +// +// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(ReceiveMessageRequest request, +// ReceiptHandle handle, String messageId, int maxReconsumeTimes) { +// return buildConsumerSendMsgBackRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle, messageId, maxReconsumeTimes); +// } +// +// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( +// ForwardMessageToDeadLetterQueueRequest request) { +// ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); +// return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, +// request.getMessageId(), request.getMaxDeliveryAttempts()); +// } +// +// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Resource topic, Resource group, ReceiptHandle handle, +// String messageId, int maxReconsumeTimes) { +// String groupName = GrpcConverter.wrapResourceWithNamespace(group); +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// +// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); +// consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); +// consumerSendMsgBackRequestHeader.setGroup(groupName); +// consumerSendMsgBackRequestHeader.setDelayLevel(-1); +// consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); +// consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); +// consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); +// return consumerSendMsgBackRequestHeader; +// } +// +// public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, +// String producerGroup) { +// String messageId = request.getMessageId(); +// String transactionId = request.getTransactionId(); +// TransactionId handle; +// try { +// handle = TransactionId.decode(transactionId); +// } catch (Exception e) { +// throw new GrpcProxyException(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); +// } +// long transactionStateTableOffset = handle.getTranStateTableOffset(); +// long commitLogOffset = handle.getCommitLogOffset(); +// boolean fromTransactionCheck = request.getSource() == TransactionSource.SOURCE_SERVER_CHECK; +// int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); +// +// EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); +// endTransactionRequestHeader.setProducerGroup(producerGroup); +// endTransactionRequestHeader.setMsgId(messageId); +// endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); +// endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); +// endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); +// endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); +// endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); +// +// return endTransactionRequestHeader; +// } +// +// public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, +// ClientType clientType, NotifyClientTerminationRequest request) { +// UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); +// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// header.setClientID(clientId); +// switch (clientType) { +// case PRODUCER: { +// header.setProducerGroup(groupName); +// break; +// } +// case PUSH_CONSUMER: +// case SIMPLE_CONSUMER: { +// header.setConsumerGroup(groupName); +// break; +// } +// } +// return header; +// } +// +// public static Map buildMessageProperty(Message message, String producerGroup) { +// org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); +// // set user properties +// Map userProperties = message.getUserPropertiesMap(); +// for (String key : userProperties.keySet()) { +// if (MessageConst.STRING_HASH_SET.contains(key)) { +// throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); +// } +// } +// MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); +// +// // set tag +// String tag = message.getSystemProperties().getTag(); +// if (!"".equals(tag)) { +// messageWithHeader.setTags(tag); +// } +// +// // set keys +// List keysList = message.getSystemProperties().getKeysList(); +// if (keysList.size() > 0) { +// messageWithHeader.setKeys(keysList); +// } +// +// // set message id +// String messageId = message.getSystemProperties().getMessageId(); +// if ("".equals(messageId)) { +// throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); +// } +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); +// +// // set transaction property +// MessageType messageType = message.getSystemProperties().getMessageType(); +// if (messageType.equals(MessageType.TRANSACTION)) { +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); +// +// Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); +// +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, +// String.valueOf(Durations.toSeconds(transactionResolveDelay))); +// } +// +// // set delay level or deliver timestamp +// if (message.getSystemProperties().hasDeliveryTimestamp()) { +// Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); +// String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); +// } +// +// // set reconsume times +// int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); +// MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); +// // set producer group +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); +// // set message group +// String messageGroup = message.getSystemProperties().getMessageGroup(); +// if (!messageGroup.isEmpty()) { +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); +// } +// // set trace context +// String traceContext = message.getSystemProperties().getTraceContext(); +// if (!traceContext.isEmpty()) { +// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); +// } +// return messageWithHeader.getProperties(); +// } +// +// public static List buildMessage(List protoMessageList, +// Resource topic) { +// String topicName = wrapResourceWithNamespace(topic); +// List messages = new ArrayList<>(); +// for (Message protoMessage : protoMessageList) { +// if (!protoMessage.getTopic().equals(topic)) { +// throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); +// } +// // here use topicName as producerGroup for transactional checker. +// messages.add(buildMessage(protoMessage, topicName)); +// } +// return messages; +// } +// +// public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage, String producerGroup) { +// String topicName = wrapResourceWithNamespace(protoMessage.getTopic()); +// +// org.apache.rocketmq.common.message.Message message = +// new org.apache.rocketmq.common.message.Message(topicName, protoMessage.getBody().toByteArray()); +// Map messageProperty = buildMessageProperty(protoMessage, producerGroup); +// +// MessageAccessor.setProperties(message, messageProperty); +// return message; +// } +// +// public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { +// Broker broker = Broker.getDefaultInstance(); +// if (!StringUtils.isEmpty(brokerName)) { +// broker = Broker.newBuilder() +// .setName(brokerName) +// .setId(0) +// .build(); +// } +// return MessageQueue.newBuilder() +// .setId(messageExt.getQueueId()) +// .setTopic(Resource.newBuilder() +// .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) +// .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) +// .build()) +// .setBroker(broker) +// .build(); +// } +// +// public static String buildExpressionType(FilterType filterType) { +// switch (filterType) { +// case SQL: +// return ExpressionType.SQL92; +// case TAG: +// default: +// return ExpressionType.TAG; +// } +// } +// +// public static Set buildSubscriptionDataSet(List subscriptionEntryList) { +// Set subscriptionDataSet = new HashSet<>(); +// for (SubscriptionEntry sub : subscriptionEntryList) { +// String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); +// FilterExpression filterExpression = sub.getExpression(); +// subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); +// } +// return subscriptionDataSet; +// } +// +// public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { +// String expression = filterExpression.getExpression(); +// String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); +// try { +// return FilterAPI.build(topicName, expression, expressionType); +// } catch (Exception e) { +// throw new GrpcProxyException(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); +// } +// } +// +// public static Message buildMessage(MessageExt messageExt) { +// Map userProperties = buildUserAttributes(messageExt); +// SystemProperties systemProperties = buildSystemProperties(messageExt); +// Resource topic = buildResource(messageExt.getTopic()); +// +// return Message.newBuilder() +// .setTopic(topic) +// .putAllUserProperties(userProperties) +// .setSystemProperties(systemProperties) +// .setBody(ByteString.copyFrom(messageExt.getBody())) +// .build(); +// } +// +// protected static Map buildUserAttributes(MessageExt messageExt) { +// Map userAttributes = new HashMap<>(); +// Map properties = messageExt.getProperties(); +// +// for (Map.Entry property : properties.entrySet()) { +// if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { +// userAttributes.put(property.getKey(), property.getValue()); +// } +// } +// +// return userAttributes; +// } +// +// protected static SystemProperties buildSystemProperties(MessageExt messageExt) { +// SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); +// +// // tag +// String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); +// if (tag != null) { +// systemPropertiesBuilder.setTag(tag); +// } +// +// // keys +// String keys = messageExt.getKeys(); +// if (keys != null) { +// String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); +// systemPropertiesBuilder.addAllKeys(Arrays.asList(keysArray)); +// } +// +// // message_id +// String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); +// if (uniqKey != null) { +// systemPropertiesBuilder.setMessageId(uniqKey); +// } +// +// // body_digest & body_encoding +// String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); +// Digest digest = Digest.newBuilder() +// .setType(DigestType.MD5) +// .setChecksum(md5Result) +// .build(); +// systemPropertiesBuilder.setBodyDigest(digest); +// +// if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { +// systemPropertiesBuilder.setBodyEncoding(Encoding.GZIP); +// } else { +// systemPropertiesBuilder.setBodyEncoding(Encoding.IDENTITY); +// } +// +// // message_type +// String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); +// String isTransValue = "true"; +// if (isTransValue.equals(isTrans)) { +// systemPropertiesBuilder.setMessageType(MessageType.TRANSACTION); +// } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null +// || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null +// || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { +// systemPropertiesBuilder.setMessageType(MessageType.DELAY); +// } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { +// systemPropertiesBuilder.setMessageType(MessageType.FIFO); +// } else { +// systemPropertiesBuilder.setMessageType(MessageType.NORMAL); +// } +// +// // born_timestamp (millis) +// long bornTimestamp = messageExt.getBornTimestamp(); +// systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); +// +// // born_host +// systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); +// +// // store_timestamp (millis) +// long storeTimestamp = messageExt.getStoreTimestamp(); +// systemPropertiesBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); +// +// // store_host +// SocketAddress storeHost = messageExt.getStoreHost(); +// if (storeHost != null) { +// systemPropertiesBuilder.setStoreHost(storeHost.toString()); +// } +// +// // delivery_timestamp +// String deliverMsString; +// long deliverMs; +// if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { +// long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); +// deliverMs = System.currentTimeMillis() + delayMs; +// systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); +// } else { +// deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); +// if (deliverMsString != null) { +// deliverMs = Long.parseLong(deliverMsString); +// systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); +// } +// } +// +// // sharding key +// String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); +// if (shardingKey != null) { +// systemPropertiesBuilder.setMessageGroup(shardingKey); +// } +// +// // receipt_handle && invisible_period +// ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); +// if (receiptHandle != null) { +// systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); +// } +// +// // partition_id +// systemPropertiesBuilder.setQueueId(messageExt.getQueueId()); +// +// // partition_offset +// systemPropertiesBuilder.setQueueOffset(messageExt.getQueueOffset()); +// +// // delivery_attempt +// systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); +// +// // trace context +// String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); +// if (traceContext != null) { +// systemPropertiesBuilder.setTraceContext(traceContext); +// } +// +// return systemPropertiesBuilder.build(); +// } +// +// public static int buildTransactionCommitOrRollback(TransactionResolution type) { +// switch (type) { +// case COMMIT: +// return MessageSysFlag.TRANSACTION_COMMIT_TYPE; +// case ROLLBACK: +// return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; +// default: +// return MessageSysFlag.TRANSACTION_NOT_TYPE; +// } +// } +// +// public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { +// ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); +// switch (request.getStatus().getCode().getNumber()) { +// case Code.OK_VALUE: { +// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); +// break; +// } +// case Code.FAILED_TO_CONSUME_MESSAGE_VALUE: { +// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); +// break; +// } +// case Code.MESSAGE_CORRUPTED_VALUE: { +// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); +// break; +// } +// } +// consumeMessageDirectlyResult.setRemark("From gRPC client"); +// return consumeMessageDirectlyResult; +// } +// +// public static Resource buildResource(String resourceNameWithNamespace) { +// return Resource.newBuilder() +// .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) +// .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) +// .build(); +// } +// +// public static long buildPollTimeFromContext(Context ctx) { +// long timeRemaining = ctx.getDeadline() +// .timeRemaining(TimeUnit.MILLISECONDS); +// long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); +// if (pollTime <= 0) { +// pollTime = timeRemaining; +// } +// +// return pollTime; +// } +// +// public static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { +// List messageQueueList = new ArrayList<>(); +// +// int r = 0; +// int w = 0; +// int rw = 0; +// if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { +// rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); +// r = queueData.getReadQueueNums() - rw; +// w = queueData.getWriteQueueNums() - rw; +// } else if (PermName.isWriteable(queueData.getPerm())) { +// w = queueData.getWriteQueueNums(); +// } else if (PermName.isReadable(queueData.getPerm())) { +// r = queueData.getReadQueueNums(); +// } +// +// // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. +// int queueIdIndex = 0; +// for (int i = 0; i < r; i++) { +// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) +// .setId(queueIdIndex++) +// .setPermission(Permission.READ) +// .build(); +// messageQueueList.add(messageQueue); +// } +// +// for (int i = 0; i < w; i++) { +// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) +// .setId(queueIdIndex++) +// .setPermission(Permission.WRITE) +// .build(); +// messageQueueList.add(messageQueue); +// } +// +// for (int i = 0; i < rw; i++) { +// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) +// .setId(queueIdIndex++) +// .setPermission(Permission.READ_WRITE) +// .build(); +// messageQueueList.add(messageQueue); +// } +// +// return messageQueueList; +// } +// +//} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyException.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyException.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyMode.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ProxyMode.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java b/proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/RequestMapping.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java similarity index 87% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java index 45fe954bda..d01abaf2ad 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/ResponseHook.java +++ b/proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java @@ -16,9 +16,9 @@ */ package org.apache.rocketmq.proxy.grpc.v2.adapter; -import io.grpc.Context; +import org.apache.rocketmq.proxy.common.ProxyContext; public interface ResponseHook { - void beforeResponse(Context ctx, T request, R response, Throwable t); + void beforeResponse(ProxyContext ctx, T request, R response, Throwable t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java b/proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/ReceiveMessageChannel.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java b/proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/channel/SendMessageChannel.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java similarity index 100% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/ResponseHandler.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java similarity index 98% rename from proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java rename to proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java index 0cbcd56a24..9ce3ddcccc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/adapter/handler/SendMessageResponseHandler.java +++ b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java @@ -28,7 +28,7 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; diff --git a/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java new file mode 100644 index 0000000000..3807409816 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java @@ -0,0 +1,99 @@ +///* +// * 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.grpc.v2.service; +// +//import apache.rocketmq.v2.Endpoints; +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import apache.rocketmq.v2.QueryAssignmentResponse; +//import apache.rocketmq.v2.QueryRouteRequest; +//import apache.rocketmq.v2.QueryRouteResponse; +//import io.grpc.Context; +//import java.util.concurrent.CompletableFuture; +//import org.apache.rocketmq.proxy.common.ParameterConverter; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.AssignmentQueueSelector; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultAssignmentQueueSelector; +// +//public abstract class AbstractRouteService extends BaseService { +// protected volatile ParameterConverter queryRouteEndpointConverter; +// protected volatile ResponseHook queryRouteHook; +// +// protected volatile ParameterConverter queryAssignmentEndpointConverter; +// protected volatile ResponseHook queryAssignmentHook; +// protected volatile AssignmentQueueSelector assignmentQueueSelector; +// +// protected final GrpcClientManager grpcClientManager; +// +// public AbstractRouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { +// super(serviceManager); +// this.grpcClientManager = grpcClientManager; +// this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; +// this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; +// this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.serviceManager.getTopicRouteService()); +// } +// +// public abstract CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); +// +// public abstract CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); +// +// public ParameterConverter getQueryRouteEndpointConverter() { +// return queryRouteEndpointConverter; +// } +// +// public void setQueryRouteEndpointConverter( +// ParameterConverter queryRouteEndpointConverter) { +// this.queryRouteEndpointConverter = queryRouteEndpointConverter; +// } +// +// public ResponseHook getQueryRouteHook() { +// return queryRouteHook; +// } +// +// public void setQueryRouteHook( +// ResponseHook queryRouteHook) { +// this.queryRouteHook = queryRouteHook; +// } +// +// public ParameterConverter getQueryAssignmentEndpointConverter() { +// return queryAssignmentEndpointConverter; +// } +// +// public void setQueryAssignmentEndpointConverter( +// ParameterConverter queryAssignmentEndpointConverter) { +// this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; +// } +// +// public AssignmentQueueSelector getAssignmentQueueSelector() { +// return assignmentQueueSelector; +// } +// +// public void setAssignmentQueueSelector( +// AssignmentQueueSelector assignmentQueueSelector) { +// this.assignmentQueueSelector = assignmentQueueSelector; +// } +// +// public ResponseHook getQueryAssignmentHook() { +// return queryAssignmentHook; +// } +// +// public void setQueryAssignmentHook( +// ResponseHook queryAssignmentHook) { +// this.queryAssignmentHook = queryAssignmentHook; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..6a65830fca --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java @@ -0,0 +1,122 @@ +///* +// * 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.grpc.v2.service; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import java.util.Iterator; +//import java.util.List; +//import org.apache.rocketmq.client.consumer.PopStatus; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +// +//public abstract class BaseReceiveMessageResponseStreamWriter { +// +// protected final StreamObserver streamObserver; +// protected final ResponseHook receiveMessageHook; +// protected final ReceiveMessageResultFilter receiveMessageResultFilter; +// +// public interface Builder { +// BaseReceiveMessageResponseStreamWriter build( +// StreamObserver observer, +// ResponseHook hook); +// } +// +// public BaseReceiveMessageResponseStreamWriter( +// StreamObserver observer, +// ResponseHook hook, +// ReceiveMessageResultFilter messageResultFilter) { +// streamObserver = observer; +// receiveMessageHook = hook; +// receiveMessageResultFilter = messageResultFilter; +// } +// +// public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { +// ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( +// ctx, +// request, +// receiveMessageHook, +// streamObserver); +// try { +// switch (status) { +// case FOUND: +// List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); +// if (messageList.isEmpty()) { +// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) +// .build()); +// } else { +// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build()); +// Iterator messageIterator = messageList.iterator(); +// while (messageIterator.hasNext()) { +// Message curMessage = messageIterator.next(); +// try { +// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() +// .setMessage(curMessage) +// .build()); +// } catch (Throwable t) { +// this.processThrowableWhenWriteMessage(t, ctx, request, curMessage); +// messageIterator.forEachRemaining(message -> +// this.processThrowableWhenWriteMessage(t, ctx, request, message)); +// return; +// } +// } +// } +// break; +// case POLLING_FULL: +// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) +// .build()); +// break; +// case NO_NEW_MSG: +// case POLLING_NOT_FOUND: +// default: +// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) +// .build()); +// break; +// } +// } catch (Throwable t) { +// write(ctx, request, t); +// } finally { +// responseStreamObserver.onCompleted(); +// } +// } +// +// protected abstract void processThrowableWhenWriteMessage(Throwable throwable, +// Context context, ReceiveMessageRequest request, Message message); +// +// public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { +// ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( +// ctx, +// request, +// receiveMessageHook, +// streamObserver); +// ResponseWriter.write( +// responseStreamObserver, +// ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() +// ); +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java new file mode 100644 index 0000000000..cf40b63772 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java @@ -0,0 +1,67 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service; +// +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.Settings; +//import io.grpc.Context; +//import java.util.ArrayList; +//import java.util.Collections; +//import java.util.List; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +//import org.apache.rocketmq.proxy.common.utils.FilterUtils; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +// +//public abstract class BaseReceiveMessageResultFilter implements ReceiveMessageResultFilter { +// +// protected final GrpcClientManager grpcClientManager; +// +// public BaseReceiveMessageResultFilter(GrpcClientManager manager) { +// grpcClientManager = manager; +// } +// +// @Override +// public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { +// if (messageExtList == null || messageExtList.isEmpty()) { +// return Collections.emptyList(); +// } +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); +// SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); +// Settings settings = grpcClientManager.getClientSettings(ctx); +// int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); +// List resMessageList = new ArrayList<>(); +// for (MessageExt messageExt : messageExtList) { +// if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { +// processNoMatchMessage(ctx, request, messageExt); +// continue; +// } +// if (messageExt.getReconsumeTimes() >= maxAttempts) { +// processExceedMaxAttemptsMessage(ctx, request, messageExt, maxAttempts); +// continue; +// } +// resMessageList.add(GrpcConverter.buildMessage(messageExt)); +// } +// return resMessageList; +// } +// +// protected abstract void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt); +// +// protected abstract void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempts); +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java new file mode 100644 index 0000000000..a1e2a904d3 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java @@ -0,0 +1,77 @@ +///* +// * 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.grpc.v2.service; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.FilterExpression; +//import apache.rocketmq.v2.Resource; +//import io.grpc.Context; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.proxy.common.StartAndShutdown; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +// +//public abstract class BaseService implements StartAndShutdown { +// +// protected final ServiceManager serviceManager; +// +// public BaseService(ServiceManager serviceManager) { +// this.serviceManager = serviceManager; +// } +// +// public static ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { +// ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); +// if (receiptHandle.isExpired()) { +// throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); +// } +// return receiptHandle; +// } +// +// public static String getBrokerAddr(Context ctx, TopicRouteService topicRouteService, String brokerName) throws Exception { +// if (StringUtils.isBlank(brokerName)) { +// throw new ProxyException(Code.UNRECOGNIZED, "broker name is empty"); +// } +// String addr = topicRouteService.getBrokerAddr(brokerName); +// if (StringUtils.isBlank(addr)) { +// throw new ProxyException(Code.UNRECOGNIZED, brokerName + " not exist"); +// } +// return addr; +// } +// +// protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { +// return getBrokerAddr(ctx, this.serviceManager.getTopicRouteService(), brokerName); +// } +// +// protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { +// // for checking filterExpression. +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// GrpcConverter.buildSubscriptionData(topicName, filterExpression); +// } +// +// @Override +// public void start() throws Exception { +// +// } +// +// @Override +// public void shutdown() throws Exception { +// +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java b/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java new file mode 100644 index 0000000000..966e4e3570 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java @@ -0,0 +1,65 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service; +// +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.Settings; +//import apache.rocketmq.v2.TelemetryCommand; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +// +//public class ClientSettingsService { +// +// private final ChannelManager channelManager; +// private final GrpcClientManager grpcClientManager; +// private final TelemetryCommandManager telemetryCommandManager; +// +// public ClientSettingsService(ChannelManager channelManager, +// GrpcClientManager grpcClientManager, +// TelemetryCommandManager telemetryCommandManager) { +// this.channelManager = channelManager; +// this.grpcClientManager = grpcClientManager; +// this.telemetryCommandManager = telemetryCommandManager; +// } +// +// public TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// grpcClientManager.updateClientSettings(clientId, request.getSettings()); +// Settings settings = grpcClientManager.getClientSettings(clientId); +// if (settings.hasPublishing()) { +// for (Resource topic : settings.getPublishing().getTopicsList()) { +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); +// producerChannel.setClientObserver(responseObserver); +// } +// } +// if (settings.hasSubscription()) { +// String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); +// GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); +// consumerChannel.setClientObserver(responseObserver); +// } +// return TelemetryCommand.newBuilder() +// .setSettings(settings) +// .build(); +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java b/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java new file mode 100644 index 0000000000..0c223d86bb --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java @@ -0,0 +1,184 @@ +///* +// * 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.grpc.v2.service; +// +//import apache.rocketmq.v2.AckMessageRequest; +//import apache.rocketmq.v2.AckMessageResponse; +//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +//import apache.rocketmq.v2.EndTransactionRequest; +//import apache.rocketmq.v2.EndTransactionResponse; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +//import apache.rocketmq.v2.HeartbeatRequest; +//import apache.rocketmq.v2.HeartbeatResponse; +//import apache.rocketmq.v2.NotifyClientTerminationRequest; +//import apache.rocketmq.v2.NotifyClientTerminationResponse; +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import apache.rocketmq.v2.QueryAssignmentResponse; +//import apache.rocketmq.v2.QueryRouteRequest; +//import apache.rocketmq.v2.QueryRouteResponse; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import apache.rocketmq.v2.SendMessageRequest; +//import apache.rocketmq.v2.SendMessageResponse; +//import apache.rocketmq.v2.TelemetryCommand; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import java.util.concurrent.CompletableFuture; +//import java.util.concurrent.Executors; +//import java.util.concurrent.ScheduledExecutorService; +//import org.apache.rocketmq.common.ThreadFactoryImpl; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +//import org.apache.rocketmq.proxy.common.StartAndShutdown; +//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; +//import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; +//import org.apache.rocketmq.proxy.grpc2.v2.GrpcMessingActivity; +// +//public class ClusterGrpcActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( +// new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") +// ); +// +// protected ChannelManager channelManager; +// protected ServiceManager serviceManager; +// protected ProducerService producerService; +// protected ConsumerService consumerService; +// protected RouteService routeService; +// protected ForwardClientService clientService; +// protected TransactionService transactionService; +// protected TelemetryCommandManager pollCommandResponseManager; +// protected GrpcClientManager grpcClientManager; +// +// public ClusterGrpcActivity() { +// this.init(); +// } +// +// protected void init() { +// this.channelManager = new ChannelManager(); +// this.grpcClientManager = new GrpcClientManager(); +// this.pollCommandResponseManager = new TelemetryCommandManager(); +// this.serviceManager = new ServiceManager(new GrpcTransactionStateChecker()); +// this.consumerService = new ConsumerService(serviceManager, grpcClientManager); +// this.producerService = new ProducerService(serviceManager); +// this.routeService = new RouteService(serviceManager, grpcClientManager); +// this.clientService = new ForwardClientService(serviceManager, scheduledExecutorService, +// channelManager, grpcClientManager, pollCommandResponseManager); +// this.transactionService = new TransactionService(serviceManager, channelManager); +// +// this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); +// this.appendStartAndShutdown(this.serviceManager); +// this.appendStartAndShutdown(this.consumerService); +// this.appendStartAndShutdown(this.producerService); +// this.appendStartAndShutdown(this.routeService); +// this.appendStartAndShutdown(this.clientService); +// this.appendStartAndShutdown(this.transactionService); +// } +// +// @Override +// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { +// return routeService.queryRoute(ctx, request); +// } +// +// @Override +// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { +// return clientService.heartbeat(ctx, request); +// } +// +// @Override +// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { +// return producerService.sendMessage(ctx, request); +// } +// +// @Override +// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { +// return routeService.queryAssignment(ctx, request); +// } +// +// @Override +// public void receiveMessage(Context ctx, ReceiveMessageRequest request, +// StreamObserver responseObserver) { +// consumerService.receiveMessage(ctx, request, responseObserver); +// } +// +// @Override +// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { +// return consumerService.ackMessage(ctx, request); +// } +// +// @Override +// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, +// ForwardMessageToDeadLetterQueueRequest request) { +// return producerService.forwardMessageToDeadLetterQueue(ctx, request); +// } +// +// @Override +// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { +// return transactionService.endTransaction(ctx, request); +// } +// +// @Override +// public CompletableFuture notifyClientTermination(Context ctx, +// NotifyClientTerminationRequest request) { +// return clientService.notifyClientTermination(ctx, request); +// } +// +// @Override +// public CompletableFuture changeInvisibleDuration(Context ctx, +// ChangeInvisibleDurationRequest request) { +// return consumerService.changeInvisibleDuration(ctx, request); +// } +// +// @Override +// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { +// return clientService.telemetry(ctx, responseObserver); +// } +// +// protected class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { +// +// @Override +// public void start() throws Exception { +// } +// +// @Override +// public void shutdown() throws Exception { +// scheduledExecutorService.shutdown(); +// } +// } +// +// protected class GrpcTransactionStateChecker implements TransactionStateChecker { +// +// @Override +// public void checkTransactionState(TransactionStateCheckRequest checkData) { +// transactionService.checkTransactionState(checkData); +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java b/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java new file mode 100644 index 0000000000..daa2977ab6 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java @@ -0,0 +1,566 @@ +///* +// * 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.grpc.v2.service; +// +//import apache.rocketmq.v2.AckMessageEntry; +//import apache.rocketmq.v2.AckMessageRequest; +//import apache.rocketmq.v2.AckMessageResponse; +//import apache.rocketmq.v2.AckMessageResultEntry; +//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.EndTransactionRequest; +//import apache.rocketmq.v2.EndTransactionResponse; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +//import apache.rocketmq.v2.HeartbeatRequest; +//import apache.rocketmq.v2.HeartbeatResponse; +//import apache.rocketmq.v2.NotifyClientTerminationRequest; +//import apache.rocketmq.v2.NotifyClientTerminationResponse; +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import apache.rocketmq.v2.QueryAssignmentResponse; +//import apache.rocketmq.v2.QueryRouteRequest; +//import apache.rocketmq.v2.QueryRouteResponse; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.SendMessageRequest; +//import apache.rocketmq.v2.SendMessageResponse; +//import apache.rocketmq.v2.Settings; +//import apache.rocketmq.v2.TelemetryCommand; +//import apache.rocketmq.v2.ThreadStackTrace; +//import apache.rocketmq.v2.VerifyMessageResult; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import io.netty.channel.Channel; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import org.apache.rocketmq.broker.BrokerController; +//import org.apache.rocketmq.broker.client.ClientChannelInfo; +//import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +//import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +//import org.apache.rocketmq.broker.client.ProducerChangeListener; +//import org.apache.rocketmq.broker.client.ProducerGroupEvent; +//import org.apache.rocketmq.client.consumer.PopStatus; +//import org.apache.rocketmq.common.MQVersion; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.message.MessageBatch; +//import org.apache.rocketmq.common.message.MessageClientIDSetter; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.message.MessageQueue; +//import org.apache.rocketmq.common.protocol.RequestCode; +//import org.apache.rocketmq.common.protocol.ResponseCode; +//import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +//import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; +//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; +//import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.channel.InvocationContext; +//import org.apache.rocketmq.proxy.channel.SimpleChannel; +//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +//import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +//import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; +//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResponseStreamWriter; +//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResultFilter; +//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; +//import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; +//import org.apache.rocketmq.proxy.grpc2.v2.GrpcMessingActivity; +//import org.apache.rocketmq.remoting.RemotingServer; +//import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; +//import org.apache.rocketmq.remoting.protocol.LanguageCode; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +// +//public class LocalGrpcActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// private final BrokerController brokerController; +// private final ChannelManager channelManager; +// private final TelemetryCommandManager telemetryCommandManager; +// private final GrpcClientManager grpcClientManager; +// private final RouteService routeService; +// private final ClientSettingsService clientSettingsService; +// private final LocalWriteQueueSelector localWriteQueueSelector; +// private final BaseReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; +// +// private volatile ResponseHook receiveMessageHook; +// +// public LocalGrpcActivity(BrokerController brokerController) { +// this(brokerController, new TelemetryCommandManager()); +// } +// +// /** +// * For unit test +// * @param brokerController BrokerController works in local mode +// * @param telemetryCommandManager Used to manage telemetry command +// */ +// LocalGrpcActivity(BrokerController brokerController, TelemetryCommandManager telemetryCommandManager) { +// this.brokerController = brokerController; +// this.channelManager = new ChannelManager(); +// // TransactionStateChecker is not used in Local mode. +// ServiceManager serviceManager = new ServiceManager(null); +// this.telemetryCommandManager = telemetryCommandManager; +// this.grpcClientManager = new GrpcClientManager(); +// this.routeService = new RouteService(serviceManager, grpcClientManager); +// this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); +// this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), +// brokerController.getTopicConfigManager(), serviceManager.getTopicRouteService()); +// +// this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); +// this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); +// +// this.streamWriterBuilder = (observer, hook) -> new LocalReceiveMessageResponseStreamWriter( +// observer, +// hook, +// channelManager, +// brokerController, +// new LocalReceiveMessageResultFilter(channelManager, brokerController, grpcClientManager) +// ); +// +// this.appendStartAndShutdown(serviceManager); +// } +// +// @Override +// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { +// return this.routeService.queryRoute(ctx, request); +// } +// +// @Override +// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { +// LanguageCode languageCode; +// String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// languageCode = LanguageCode.valueOf(language); +// +// Settings clientSettings = grpcClientManager.getClientSettings(clientId); +// HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); +// command.setLanguage(languageCode); +// command.setVersion(MQVersion.Version.V5_0_0.ordinal()); +// command.setBody(heartbeatData.encode()); +// command.makeCustomHeaderToNet(); +// +// CompletableFuture future = new CompletableFuture<>(); +// switch (clientSettings.getClientType()) { +// case PRODUCER: { +// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); +// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); +// +// this.brokerController.getClientManageProcessor() +// .heartBeat(simpleChannelHandlerContext, command); +// } +// HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, "Producer heartbeat")) +// .build(); +// future.complete(heartbeatResponse); +// break; +// } +// case PUSH_CONSUMER: +// case SIMPLE_CONSUMER: { +// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); +// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); +// +// RemotingCommand response = this.brokerController.getClientManageProcessor() +// .heartBeat(simpleChannelHandlerContext, command); +// HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) +// .build(); +// future.complete(heartbeatResponse); +// break; +// } +// default: { +// throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); +// } +// } +// +// return future; +// } +// +// @Override +// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { +// MessageQueue messageQueue = localWriteQueueSelector.selectQueue(ctx, request).getMessageQueue(); +// String topicName = messageQueue.getTopic(); +// SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName, messageQueue.getQueueId()); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); +// List messageList = GrpcConverter.buildMessage(request.getMessagesList(), request.getMessages(0).getTopic()); +// String messageId; +// if (messageList.size() == 1) { +// org.apache.rocketmq.common.message.Message message = messageList.get(0); +// command.setBody(message.getBody()); +// messageId = MessageClientIDSetter.getUniqID(message); +// } else { +// MessageBatch messageBatch = MessageBatch.generateFromList(messageList); +// MessageClientIDSetter.setUniqID(messageBatch); +// messageBatch.setBody(messageBatch.encode()); +// command.setBody(messageBatch.encode()); +// messageId = MessageClientIDSetter.getUniqID(messageBatch); +// } +// command.makeCustomHeaderToNet(); +// +// SendMessageResponseHandler handler = new SendMessageResponseHandler(messageId, requestHeader.getSysFlag(), brokerController.getBrokerAddr()); +// SendMessageChannel channel = channelManager.createChannel(ctx, context -> new SendMessageChannel(context, handler), SendMessageChannel.class); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// CompletableFuture future = new CompletableFuture<>(); +// InvocationContext context +// = new InvocationContext<>(request, future); +// channel.registerInvocationContext(command.getOpaque(), context); +// try { +// RemotingCommand response = brokerController.getSendMessageProcessor() +// .processRequest(channelHandlerContext, command); +// if (response != null) { +// handler.handle(response, context); +// channel.eraseInvocationContext(command.getOpaque()); +// } +// } catch (final Exception e) { +// log.error("Failed to process send message command", e); +// channel.eraseInvocationContext(command.getOpaque()); +// future.completeExceptionally(e); +// } +// return future; +// } +// +// @Override +// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { +// return this.routeService.queryAssignment(ctx, request); +// } +// +// @Override +// public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { +// long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); +// // TODO: get fifo config from subscriptionGroupManager +// boolean fifo = false; +// BaseReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); +// ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); +// ReceiveMessageChannel channel = channelManager.createChannel(ctx, context -> new ReceiveMessageChannel(context, handler), ReceiveMessageChannel.class); +// CompletableFuture> future = new CompletableFuture<>(); +// InvocationContext> context +// = new InvocationContext<>(request, future); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); +// command.makeCustomHeaderToNet(); +// channel.registerInvocationContext(command.getOpaque(), context); +// try { +// RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(channelHandlerContext, command); +// if (response != null) { +// handler.handle(response, context); +// channel.eraseInvocationContext(command.getOpaque()); +// } +// } catch (Exception e) { +// log.error("Failed to process pop message command", e); +// channel.eraseInvocationContext(command.getOpaque()); +// future.completeExceptionally(e); +// } +// future.thenAccept(r -> writer.write(ctx, request, PopStatus.FOUND, r)) +// .exceptionally(e -> { +// writer.write(ctx, request, e); +// return null; +// }); +// } +// +// @Override +// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// CompletableFuture future = new CompletableFuture<>(); +// List ackMessageResultEntryList = new ArrayList<>(); +// for (AckMessageEntry entry : request.getEntriesList()) { +// ReceiptHandle receiptHandle = ReceiptHandle.decode(entry.getReceiptHandle()); +// if (receiptHandle.isExpired()) { +// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() +// .setReceiptHandle(entry.getReceiptHandle()) +// .setMessageId(entry.getMessageId()) +// .setStatus(ResponseBuilder.buildStatus(Code.RECEIPT_HANDLE_EXPIRED, "expired")) +// .build()); +// continue; +// } +// AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, receiptHandle); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); +// command.makeCustomHeaderToNet(); +// +// try { +// RemotingCommand responseCommand = brokerController.getAckMessageProcessor() +// .processRequest(channelHandlerContext, command); +// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() +// .setReceiptHandle(entry.getReceiptHandle()) +// .setMessageId(entry.getMessageId()) +// .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) +// .build()); +// } catch (Exception e) { +// log.error("Exception raised when ack message", e); +// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() +// .setReceiptHandle(entry.getReceiptHandle()) +// .setMessageId(entry.getMessageId()) +// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, e.getMessage())) +// .build()); +// } +// } +// AckMessageResponse response = AckMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, "ok")) +// .addAllEntries(ackMessageResultEntryList) +// .build(); +// future.complete(response); +// return future; +// } +// +// @Override +// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, +// ForwardMessageToDeadLetterQueueRequest request) { +// SimpleChannel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// +// ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); +// command.makeCustomHeaderToNet(); +// +// CompletableFuture future = new CompletableFuture<>(); +// try { +// RemotingCommand response = brokerController.getSendMessageProcessor() +// .processRequest(channelHandlerContext, command); +// +// future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) +// .build()); +// } catch (Exception e) { +// log.error("Exception raised when forwardMessageToDeadLetterQueue", e); +// future.completeExceptionally(e); +// } +// return future; +// } +// +// @Override +// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request, topicName); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); +// command.makeCustomHeaderToNet(); +// +// CompletableFuture future = new CompletableFuture<>(); +// try { +// RemotingCommand responseCommand = brokerController.getEndTransactionProcessor() +// .processRequest(channelHandlerContext, command); +// EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); +// if (null != responseCommand) { +// builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); +// } else { +// builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); +// } +// EndTransactionResponse response = builder.build(); +// future.complete(response); +// } catch (Exception e) { +// log.error("Exception raised while endTransaction", e); +// future.completeExceptionally(e); +// } +// return future; +// } +// +// public void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { +// String nonce = request.getNonce(); +// String threadStack = request.getThreadStackTrace(); +// TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); +// if (pollCommandResponseFuture != null) { +// Integer opaque = pollCommandResponseFuture.getOpaque(); +// if (opaque != null) { +// RemotingServer remotingServer = this.brokerController.getRemotingServer(); +// if (remotingServer instanceof NettyRemotingAbstract) { +// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); +// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); +// ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); +// runningInfo.setJstack(threadStack); +// remotingCommand.setBody(runningInfo.encode()); +// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); +// } +// } +// } +// } +// +// public void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { +// String nonce = request.getNonce(); +// TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); +// if (pollCommandResponseFuture != null) { +// Integer opaque = pollCommandResponseFuture.getOpaque(); +// if (opaque != null) { +// RemotingServer remotingServer = this.brokerController.getRemotingServer(); +// if (remotingServer instanceof NettyRemotingAbstract) { +// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); +// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); +// ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); +// remotingCommand.setBody(result.encode()); +// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); +// } +// } +// } +// } +// +// @Override +// public CompletableFuture notifyClientTermination(Context ctx, +// NotifyClientTerminationRequest request) { +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// Settings clientSettings = grpcClientManager.getClientSettings(clientId); +// UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); +// +// RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); +// remotingCommand.makeCustomHeaderToNet(); +// try { +// this.brokerController.getClientManageProcessor().unregisterClient(simpleChannelHandlerContext, remotingCommand); +// } catch (Exception ignored) { +// } +// return new CompletableFuture<>(); +// } +// +// @Override +// public CompletableFuture changeInvisibleDuration(Context ctx, +// ChangeInvisibleDurationRequest request) { +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); +// +// ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); +// ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); +// command.makeCustomHeaderToNet(); +// +// CompletableFuture future = new CompletableFuture<>(); +// try { +// RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() +// .processRequest(channelHandlerContext, command); +// ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); +// ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); +// if (responseCommand.getCode() == ResponseCode.SUCCESS) { +// builder.setReceiptHandle(ReceiptHandle.builder() +// .startOffset(requestHeader.getOffset()) +// .retrieveTime(responseHeader.getPopTime()) +// .invisibleTime(responseHeader.getInvisibleTime()) +// .reviveQueueId(responseHeader.getReviveQid()) +// .topicType(receiptHandle.getTopicType()) +// .brokerName(brokerController.getBrokerConfig().getBrokerName()) +// .queueId(requestHeader.getQueueId()) +// .offset(requestHeader.getOffset()) +// .build() +// .encode()); +// } +// +// future.complete(builder.build()); +// } catch (Exception e) { +// log.error("Exception raised while changeInvisibleDuration", e); +// future.completeExceptionally(e); +// } +// return future; +// } +// +// @Override +// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// return new StreamObserver() { +// @Override +// public void onNext(TelemetryCommand request) { +// switch (request.getCommandCase()) { +// case SETTINGS: { +// responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); +// break; +// } +// case THREAD_STACK_TRACE: { +// reportThreadStackTrace(ctx, request.getThreadStackTrace()); +// break; +// } +// case VERIFY_MESSAGE_RESULT: { +// reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); +// break; +// } +// default: { +// throw new IllegalArgumentException("Request type is illegal"); +// } +// } +// } +// +// @Override +// public void onError(Throwable t) { +// +// } +// +// @Override +// public void onCompleted() { +// responseObserver.onCompleted(); +// } +// }; +// } +// +// protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { +// +// @Override +// public void handle(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]; +// channelManager.onClientOffline(clientChannelInfo.getClientId()); +// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); +// } +// } +// } +// +// @Override +// public void shutdown() { +// +// } +// } +// +// protected class ProducerChangeListenerImpl implements ProducerChangeListener { +// +// @Override +// public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { +// if (event == ProducerGroupEvent.CLIENT_UNREGISTER) { +// channelManager.onClientOffline(clientChannelInfo.getClientId()); +// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); +// } +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java new file mode 100644 index 0000000000..2f36081448 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java @@ -0,0 +1,67 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service; +// +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.stub.StreamObserver; +//import org.apache.rocketmq.proxy.common.ProxyContext; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; +// +//public class ReceiveMessageResponseStreamObserver implements StreamObserver { +// +// private final ProxyContext context; +// private final ReceiveMessageRequest request; +// private final ResponseHook receiveMessageHook; +// private final StreamObserver observer; +// +// public ReceiveMessageResponseStreamObserver(ProxyContext context, ReceiveMessageRequest request, +// ResponseHook receiveMessageHook, +// StreamObserver observer) { +// this.context = context; +// this.request = request; +// this.receiveMessageHook = receiveMessageHook; +// this.observer = observer; +// } +// +// @Override +// public void onNext(ReceiveMessageResponse response) { +// if (receiveMessageHook != null) { +// receiveMessageHook.beforeResponse(context, request, response, null); +// } +// observer.onNext(response); +// } +// +// @Override +// public void onError(Throwable throwable) { +// if (receiveMessageHook != null) { +// receiveMessageHook.beforeResponse(context, request, null, throwable); +// } +// observer.onError(throwable); +// } +// +// @Override +// public void onCompleted() { +// observer.onCompleted(); +// } +// +// public boolean isCancelled() { +// return ResponseWriter.isCancelled(observer); +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java new file mode 100644 index 0000000000..f837861968 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java @@ -0,0 +1,29 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service; +// +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import io.grpc.Context; +//import java.util.List; +//import org.apache.rocketmq.common.message.MessageExt; +// +//public interface ReceiveMessageResultFilter { +// +// List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList); +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java new file mode 100644 index 0000000000..d065a9cf1d --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java @@ -0,0 +1,27 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import io.grpc.Context; +//import java.util.List; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +// +//public interface AssignmentQueueSelector { +// +// List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception; +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java new file mode 100644 index 0000000000..2db4f9b1b7 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java @@ -0,0 +1,283 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.AckMessageEntry; +//import apache.rocketmq.v2.AckMessageRequest; +//import apache.rocketmq.v2.AckMessageResponse; +//import apache.rocketmq.v2.AckMessageResultEntry; +//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import org.apache.rocketmq.client.consumer.AckResult; +//import org.apache.rocketmq.client.consumer.AckStatus; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.ForwardProducer; +//import org.apache.rocketmq.proxy.service.ForwardReadConsumer; +//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; +// +//public class ConsumerService extends BaseService { +// protected final ForwardReadConsumer readConsumer; +// protected final ForwardWriteConsumer writeConsumer; +// /** +// * For sending messages back to broker. +// */ +// protected final ForwardProducer producer; +// protected final GrpcClientManager grpcClientManager; +// +// private volatile ReadQueueSelector readQueueSelector; +// private volatile BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; +// +// private volatile ResponseHook receiveMessageHook; +// private volatile ResponseHook ackMessageHook; +// private volatile ResponseHook changeInvisibleDurationHook; +// +// public ConsumerService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { +// super(serviceManager); +// this.readConsumer = serviceManager.getForwardReadConsumer(); +// this.writeConsumer = serviceManager.getForwardWriteConsumer(); +// this.producer = serviceManager.getForwardProducer(); +// this.grpcClientManager = grpcClientManager; +// +// this.readQueueSelector = new DefaultReadQueueSelector(serviceManager.getTopicRouteService()); +// this.receiveMessageWriterBuilder = (observer, hook) -> new DefaultReceiveMessageResponseStreamWriter( +// observer, +// hook, +// writeConsumer, +// serviceManager.getTopicRouteService(), +// new DefaultReceiveMessageResultFilter( +// producer, writeConsumer, grpcClientManager, serviceManager.getTopicRouteService()) +// ); +// } +// +// public void receiveMessage(Context ctx, ReceiveMessageRequest request, +// StreamObserver responseObserver) { +// BaseReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); +// try { +// PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); +// SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); +// +// if (messageQueue == null) { +// throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); +// } +// +// this.readConsumer.popMessage( +// ctx, +// messageQueue.getBrokerAddr(), +// messageQueue.getBrokerName(), +// requestHeader, +// requestHeader.getPollTime()) +// .thenAccept(result -> writer.write(ctx, request, result.getPopStatus(), result.getMsgFoundList())) +// .exceptionally(e -> { +// writer.write(ctx, request, e); +// return null; +// }); +// } catch (Throwable t) { +// writer.write(ctx, request, t); +// } +// } +// +// protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { +// checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); +// boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); +// return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); +// } +// +// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (ackMessageHook != null) { +// ackMessageHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; +// for (int i = 0; i < request.getEntriesCount(); i++) { +// futures[i] = processAckMessage(ctx, request, request.getEntries(i)); +// } +// CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { +// if (throwable != null) { +// future.completeExceptionally(throwable); +// return; +// } +// List entryList = new ArrayList<>(); +// for (CompletableFuture entryFuture : futures) { +// entryFuture.thenAccept(entryList::add); +// } +// AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .addAllEntries(entryList); +// future.complete(responseBuilder.build()); +// }); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +// +// protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, +// AckMessageEntry ackMessageEntry) { +// CompletableFuture future = new CompletableFuture<>(); +// AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) +// .setMessageId(ackMessageEntry.getMessageId()) +// .setReceiptHandle(ackMessageEntry.getReceiptHandle()); +// +// try { +// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); +// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); +// +// AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); +// CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageEntry.getMessageId(), requestHeader); +// ackResultFuture +// .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) +// .exceptionally(throwable -> { +// future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); +// return null; +// }); +// } catch (Throwable t) { +// future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); +// } +// return future; +// } +// +// protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, +// ReceiptHandle handle) { +// return GrpcConverter.buildAckMessageRequestHeader(request, handle); +// } +// +// protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, +// AckResult ackResult) { +// if (AckStatus.OK.equals(ackResult.getStatus())) { +// return AckMessageResultEntry.newBuilder() +// .setMessageId(ackMessageEntry.getMessageId()) +// .setReceiptHandle(ackMessageEntry.getReceiptHandle()) +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build(); +// } +// return AckMessageResultEntry.newBuilder() +// .setMessageId(ackMessageEntry.getMessageId()) +// .setReceiptHandle(ackMessageEntry.getReceiptHandle()) +// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) +// .build(); +// } +// +// public CompletableFuture changeInvisibleDuration(Context ctx, +// ChangeInvisibleDurationRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// +// try { +// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); +// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); +// +// ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); +// future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), +// request.getMessageId(), requestHeader) +// .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// future.whenComplete((response, throwable) -> { +// if (changeInvisibleDurationHook != null) { +// changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// return future; +// } +// +// protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, +// ChangeInvisibleDurationRequest request) { +// return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); +// } +// +// protected ChangeInvisibleDurationResponse convertToChangeInvisibleDurationResponse(Context ctx, +// ChangeInvisibleDurationRequest request, AckResult ackResult) { +// if (AckStatus.OK.equals(ackResult.getStatus())) { +// return ChangeInvisibleDurationResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .setReceiptHandle(ackResult.getExtraInfo()) +// .build(); +// } +// return ChangeInvisibleDurationResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) +// .build(); +// } +// +// public ReadQueueSelector getReadQueueSelector() { +// return readQueueSelector; +// } +// +// public void setReadQueueSelector(ReadQueueSelector readQueueSelector) { +// this.readQueueSelector = readQueueSelector; +// } +// +// public BaseReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { +// return receiveMessageWriterBuilder; +// } +// +// public void setReceiveMessageWriterBuilder( +// BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { +// this.receiveMessageWriterBuilder = receiveMessageWriterBuilder; +// } +// +// public ResponseHook getReceiveMessageHook() { +// return receiveMessageHook; +// } +// +// public void setReceiveMessageHook( +// ResponseHook receiveMessageHook) { +// this.receiveMessageHook = receiveMessageHook; +// } +// +// public ResponseHook getAckMessageHook() { +// return ackMessageHook; +// } +// +// public void setAckMessageHook( +// ResponseHook ackMessageHook) { +// this.ackMessageHook = ackMessageHook; +// } +// +// public ResponseHook getChangeInvisibleDurationHook() { +// return changeInvisibleDurationHook; +// } +// +// public void setChangeInvisibleDurationHook( +// ResponseHook changeInvisibleDurationHook) { +// this.changeInvisibleDurationHook = changeInvisibleDurationHook; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java new file mode 100644 index 0000000000..87bc8cc0ad --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java @@ -0,0 +1,41 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import io.grpc.Context; +//import java.util.List; +//import org.apache.rocketmq.proxy.service.route.MessageQueueView; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +// +//public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { +// +// private final TopicRouteService topicRouteService; +// +// public DefaultAssignmentQueueSelector(TopicRouteService topicRouteService) { +// this.topicRouteService = topicRouteService; +// } +// +// @Override +// public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// MessageQueueView messageQueueView = topicRouteService.getAllMessageQueueView(topicName); +// return messageQueueView.getReadSelector().getBrokerActingQueues(); +// } +//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java new file mode 100644 index 0000000000..ecc4b2988c --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java @@ -0,0 +1,55 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import io.grpc.Context; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +// +//public class DefaultReadQueueSelector implements ReadQueueSelector { +// +// private final TopicRouteService topicRouteService; +// +// public DefaultReadQueueSelector(TopicRouteService topicRouteService) { +// this.topicRouteService = topicRouteService; +// } +// +// @Override +// public SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader) { +// SelectableMessageQueue messageQueue = null; +// try { +// String topic = requestHeader.getTopic(); +// +// if (request.hasMessageQueue() && request.getMessageQueue().hasBroker()) { +// String brokerName = request.getMessageQueue().getBroker().getName(); +// if (StringUtils.isNotBlank(brokerName)) { +// messageQueue = topicRouteService.selectReadBrokerByName(topic, brokerName); +// } +// } +// +// if (messageQueue == null) { +// messageQueue = topicRouteService.selectOneReadBroker(topic, null); +// } +// return messageQueue; +// } catch (Throwable t) { +// return null; +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..09c57539ba --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java @@ -0,0 +1,96 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import java.time.Duration; +//import org.apache.rocketmq.client.consumer.AckStatus; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; +//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +// +//public class DefaultReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { +// protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); +// protected final ForwardWriteConsumer writeConsumer; +// protected final TopicRouteService topicRouteService; +// +// public DefaultReceiveMessageResponseStreamWriter( +// StreamObserver observer, +// ResponseHook hook, +// ForwardWriteConsumer writeConsumer, +// TopicRouteService topicRouteService, +// ReceiveMessageResultFilter receiveMessageResultFilter) { +// super(observer, hook, receiveMessageResultFilter); +// this.writeConsumer = writeConsumer; +// this.topicRouteService = topicRouteService; +// } +// +// @Override +// protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, +// Message message) { +// this.nackFailToWriteMessage(context, request, message); +// } +// +// protected void nackFailToWriteMessage(Context ctx, ReceiveMessageRequest request, Message message) { +// try { +// String receiptHandleStr = message.getSystemProperties().getReceiptHandle(); +// ReceiptHandle handle = BaseService.resolveReceiptHandle(ctx, receiptHandleStr); +// String brokerAddr = BaseService.getBrokerAddr(ctx, this.topicRouteService, handle.getBrokerName()); +// +// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); +// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); +// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); +// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); +// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); +// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); +// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); +// changeInvisibleTimeRequestHeader.setInvisibleTime(NACK_INVISIBLE_TIME); +// +// this.writeConsumer.changeInvisibleTimeAsync( +// ctx, +// brokerAddr, +// handle.getBrokerName(), +// message.getSystemProperties().getMessageId(), +// changeInvisibleTimeRequestHeader +// ).whenComplete((ackResult, t) -> { +// if (t != null) { +// log.warn("err when nack message. request:{}, message:{}", request, message, t); +// } else if (!AckStatus.OK.equals(ackResult.getStatus())) { +// log.warn("nack failed. request:{}, message:{}, ackResult:{}", request, message, ackResult); +// } +// }); +// } catch (Throwable t) { +// log.warn("err when nack message. request:{}, message:{}", request, message, t); +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java new file mode 100644 index 0000000000..15c8bfe864 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java @@ -0,0 +1,127 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import io.grpc.Context; +//import java.util.concurrent.CompletableFuture; +//import org.apache.rocketmq.client.consumer.AckResult; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +//import org.apache.rocketmq.proxy.service.ForwardProducer; +//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +// +//import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; +// +//public class DefaultReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { +// +// protected final ForwardProducer producer; +// protected final ForwardWriteConsumer writeConsumer; +// protected final TopicRouteService topicRouteService; +// +// private volatile ResponseHook ackNoMatchedMessageHook; +// private volatile ResponseHook forwardToDLQInRecvMessageHook; +// +// public DefaultReceiveMessageResultFilter(ForwardProducer producer, ForwardWriteConsumer writeConsumer, +// GrpcClientManager grpcClientManager, TopicRouteService topicRouteService) { +// super(grpcClientManager); +// this.producer = producer; +// this.writeConsumer = writeConsumer; +// this.topicRouteService = topicRouteService; +// } +// +// @Override +// protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { +// CompletableFuture future = new CompletableFuture<>(); +// +// ReceiptHandle handle = ReceiptHandle.create(messageExt); +// if (handle == null) { +// return; +// } +// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); +// try { +// String brokerAddr = getBrokerAddr(ctx, topicRouteService, handle.getBrokerName()); +// future = this.writeConsumer.ackMessage(ctx, brokerAddr, messageExt.getMsgId(), ackMessageRequestHeader); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// +// future.whenComplete((ackResult, throwable) -> { +// if (ackNoMatchedMessageHook != null) { +// ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); +// } +// }); +// } +// +// @Override +// protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, +// int maxAttempts) { +// CompletableFuture future = new CompletableFuture<>(); +// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); +// +// try { +// ReceiptHandle handle = ReceiptHandle.create(messageExt); +// if (handle == null) { +// return; +// } +// String brokerAddr = getBrokerAddr(ctx, topicRouteService, handle.getBrokerName()); +// ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( +// request, +// handle, +// messageExt.getMsgId(), +// maxAttempts); +// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); +// +// future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// +// future.whenComplete((result, throwable) -> { +// if (forwardToDLQInRecvMessageHook != null) { +// forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); +// } +// }); +// } +// +// public ResponseHook getAckNoMatchedMessageHook() { +// return ackNoMatchedMessageHook; +// } +// +// public void setAckNoMatchedMessageHook( +// ResponseHook ackNoMatchedMessageHook) { +// this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; +// } +// +// public ResponseHook getForwardToDLQInRecvMessageHook() { +// return forwardToDLQInRecvMessageHook; +// } +// +// public void setForwardToDLQInRecvMessageHook( +// ResponseHook forwardToDLQInRecvMessageHook) { +// this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java new file mode 100644 index 0000000000..ab48b6fdac --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java @@ -0,0 +1,77 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.SendMessageRequest; +//import io.grpc.Context; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +// +//public class DefaultWriteQueueSelector implements WriteQueueSelector { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// protected final TopicRouteService topicRouteService; +// +// public DefaultWriteQueueSelector(TopicRouteService topicRouteService) { +// this.topicRouteService = topicRouteService; +// } +// +// @Override +// public SelectableMessageQueue selectQueue( +// Context ctx, +// SendMessageRequest request +// ) { +// try { +// if (request.getMessagesCount() <= 0) { +// throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); +// } +// Message message = request.getMessages(0); +// String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); +// String shardingKey = null; +// if (request.getMessagesCount() == 1) { +// shardingKey = message.getSystemProperties().getMessageGroup(); +// } +// SelectableMessageQueue targetMessageQueue; +// if (StringUtils.isNotEmpty(shardingKey)) { +// // With shardingKey +// targetMessageQueue = selectOrderQueue(topic, shardingKey); +// } else { +// targetMessageQueue = selectNormalQueue(topic); +// } +// return targetMessageQueue; +// } catch (Exception e) { +// log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); +// return null; +// } +// } +// +// protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { +// return this.topicRouteService.selectOneWriteQueue(topic, null); +// } +// +// protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { +// return this.topicRouteService.selectOneWriteQueueByKey(topic, shardingKey); +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java new file mode 100644 index 0000000000..d5dcbbdd75 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java @@ -0,0 +1,266 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.HeartbeatRequest; +//import apache.rocketmq.v2.HeartbeatResponse; +//import apache.rocketmq.v2.NotifyClientTerminationRequest; +//import apache.rocketmq.v2.NotifyClientTerminationResponse; +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.Settings; +//import apache.rocketmq.v2.TelemetryCommand; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import java.time.Duration; +//import java.util.concurrent.CompletableFuture; +//import java.util.concurrent.ScheduledExecutorService; +//import java.util.concurrent.TimeUnit; +//import org.apache.rocketmq.broker.client.ClientChannelInfo; +//import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +//import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +//import org.apache.rocketmq.broker.client.ConsumerManager; +//import org.apache.rocketmq.broker.client.ProducerChangeListener; +//import org.apache.rocketmq.broker.client.ProducerGroupEvent; +//import org.apache.rocketmq.broker.client.ProducerManager; +//import org.apache.rocketmq.common.MQVersion; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +//import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; +//import org.apache.rocketmq.remoting.protocol.LanguageCode; +// +//public class ForwardClientService extends BaseService { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// protected final ChannelManager channelManager; +// protected final GrpcClientManager grpcClientManager; +// protected final TelemetryCommandManager telemetryCommandManager; +// +// protected ConsumerManager consumerManager; +// protected ProducerManager producerManager; +// protected ClientSettingsService clientSettingsService; +// +// public ForwardClientService( +// ServiceManager serviceManager, +// ScheduledExecutorService scheduledExecutorService, +// ChannelManager channelManager, +// GrpcClientManager grpcClientManager, +// TelemetryCommandManager telemetryCommandManager +// ) { +// super(serviceManager); +// scheduledExecutorService.scheduleWithFixedDelay( +// this::scanNotActiveChannel, +// Duration.ofSeconds(10).toMillis(), +// Duration.ofSeconds(10).toMillis(), +// TimeUnit.MILLISECONDS); +// this.channelManager = channelManager; +// this.grpcClientManager = grpcClientManager; +// this.telemetryCommandManager = telemetryCommandManager; +// +// this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); +// this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); +// this.producerManager = new ProducerManager(); +// this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); +// } +// +// protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { +// +// @Override +// public void handle(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]; +// channelManager.onClientOffline(clientChannelInfo.getClientId()); +// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); +// } +// } +// } +// +// @Override +// public void shutdown() { +// +// } +// } +// +// protected class ProducerChangeListenerImpl implements ProducerChangeListener { +// +// @Override +// public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { +// switch (event) { +// case GROUP_UNREGISTER: +// serviceManager.getTransactionHeartbeatRegisterService().onProducerGroupOffline(group); +// break; +// case CLIENT_UNREGISTER: +// channelManager.onClientOffline(clientChannelInfo.getClientId()); +// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); +// break; +// default: +// break; +// } +// } +// } +// +// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// +// try { +// String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// LanguageCode languageCode = LanguageCode.valueOf(language); +// +// Settings clientSettings = grpcClientManager.getClientSettings(clientId); +// switch (clientSettings.getClientType()) { +// case PRODUCER: { +// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); +// ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); +// // use topic name as producer group +// producerManager.registerProducer(topicName, clientChannelInfo); +// serviceManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); +// } +// break; +// } +// case PUSH_CONSUMER: +// case SIMPLE_CONSUMER: { +// if (!request.hasGroup()) { +// throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); +// } +// String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, telemetryCommandManager); +// ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); +// +// consumerManager.registerConsumer( +// consumerGroup, +// clientChannelInfo, +// GrpcConverter.buildConsumeType(clientSettings.getClientType()), +// MessageModel.CLUSTERING, +// ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, +// GrpcConverter.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()), +// false +// ); +// break; +// } +// default: { +// throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); +// } +// } +// future.complete(HeartbeatResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build()); +// return future; +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +// +// public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// +// try { +// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); +// Settings clientSettings = grpcClientManager.getClientSettings(clientId); +// +// switch (clientSettings.getClientType()) { +// case PRODUCER: +// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// // user topic name as producer group +// GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); +// if (channel != null) { +// producerManager.doChannelCloseEvent(topicName, channel); +// } +// } +// break; +// case PUSH_CONSUMER: +// case SIMPLE_CONSUMER: +// if (!request.hasGroup()) { +// throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); +// } +// String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); +// GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); +// if (channel != null) { +// consumerManager.doChannelCloseEvent(consumerGroup, channel); +// } +// break; +// default: +// break; +// } +// future.complete(NotifyClientTerminationResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build()); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +// +// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { +// return new StreamObserver() { +// @Override +// public void onNext(TelemetryCommand request) { +// if (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) { +// responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); +// } +// } +// +// @Override +// public void onError(Throwable t) { +// +// } +// +// @Override +// public void onCompleted() { +// responseObserver.onCompleted(); +// } +// }; +// } +// +// private void scanNotActiveChannel() { +// try { +// this.consumerManager.scanNotActiveChannel(); +// this.producerManager.scanNotActiveChannel(); +// } catch (Exception e) { +// log.error("error occurred when scan not active client channels.", e); +// } +// } +// +// public ConsumerManager getConsumerManager() { +// return consumerManager; +// } +// +// public ProducerManager getProducerManager() { +// return producerManager; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java new file mode 100644 index 0000000000..a6d851bb10 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java @@ -0,0 +1,184 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.SendMessageRequest; +//import apache.rocketmq.v2.SendMessageResponse; +//import apache.rocketmq.v2.SendReceipt; +//import com.beust.jcommander.internal.Lists; +//import io.grpc.Context; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.client.producer.SendResult; +//import org.apache.rocketmq.client.producer.SendStatus; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.ForwardProducer; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +// +//public class ProducerService extends BaseService { +// +// protected final ForwardProducer producer; +// private volatile WriteQueueSelector writeQueueSelector; +// private volatile ResponseHook sendMessageHook; +// private volatile ResponseHook forwardMessageToDLQHook; +// +// public ProducerService(ServiceManager serviceManager) { +// super(serviceManager); +// this.producer = serviceManager.getForwardProducer(); +// +// this.writeQueueSelector = new DefaultWriteQueueSelector(this.serviceManager.getTopicRouteService()); +// } +// +// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// +// try { +// SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request); +// if (selectableMessageQueue == null) { +// throw new ProxyException(Code.FORBIDDEN, "no writeable topic route"); +// } +// +// // send message to broker. +// future = this.producer.sendMessage( +// ctx, +// selectableMessageQueue.getBrokerAddr(), +// selectableMessageQueue.getBrokerName(), +// convertToMessageList(ctx, request), +// convertToSendMessageRequestHeader(ctx, request, selectableMessageQueue) +// ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// +// future.whenComplete((response, throwable) -> { +// if (sendMessageHook != null) { +// sendMessageHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// return future; +// } +// +// protected SendMessageRequestHeader convertToSendMessageRequestHeader(Context ctx, SendMessageRequest request, SelectableMessageQueue selectableMessageQueue) { +// // use topic name as group +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessages(0).getTopic()); +// return GrpcConverter.buildSendMessageRequestHeader(request, topicName, +// selectableMessageQueue.getQueueId()); +// } +// +// protected List convertToMessageList(Context ctx, SendMessageRequest request) { +// // use topic name as group +// Resource topic = request.getMessages(0).getTopic(); +// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); +// return GrpcConverter.buildMessage(request.getMessagesList(), topic); +// } +// +// protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, +// SendResult result) { +// if (result.getSendStatus() != SendStatus.SEND_OK) { +// return SendMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) +// .build(); +// } +// +// List sendReceiptList = Lists.newArrayList(); +// sendReceiptList.add(SendReceipt.newBuilder() +// .setMessageId(StringUtils.defaultString(result.getMsgId())) +// .setTransactionId(StringUtils.defaultString(result.getTransactionId())) +// .build()); +// return SendMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .addAllReceipts(sendReceiptList) +// .build(); +// } +// +// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, +// ForwardMessageToDeadLetterQueueRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// +// try { +// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); +// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); +// ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); +// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( +// request.getTopic(), request.getGroup(), receiptHandle); +// +// future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) +// .thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// future.whenComplete((response, throwable) -> { +// if (forwardMessageToDLQHook != null) { +// forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// return future; +// } +// +// protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, +// ForwardMessageToDeadLetterQueueRequest request) { +// return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); +// } +// +// protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, +// RemotingCommand result) { +// return ForwardMessageToDeadLetterQueueResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) +// .build(); +// } +// +// public WriteQueueSelector getWriteQueueSelector() { +// return writeQueueSelector; +// } +// +// public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { +// this.writeQueueSelector = writeQueueSelector; +// } +// +// public ResponseHook getSendMessageHook() { +// return sendMessageHook; +// } +// +// public void setSendMessageHook( +// ResponseHook sendMessageHook) { +// this.sendMessageHook = sendMessageHook; +// } +// +// public ResponseHook getForwardMessageToDLQHook() { +// return forwardMessageToDLQHook; +// } +// +// public void setForwardMessageToDLQHook( +// ResponseHook forwardMessageToDLQHook) { +// this.forwardMessageToDLQHook = forwardMessageToDLQHook; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java new file mode 100644 index 0000000000..ea0e078b84 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java @@ -0,0 +1,27 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import io.grpc.Context; +//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +// +//public interface ReadQueueSelector { +// +// SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader); +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java new file mode 100644 index 0000000000..6a65c036f8 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java @@ -0,0 +1,150 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Assignment; +//import apache.rocketmq.v2.Broker; +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Endpoints; +//import apache.rocketmq.v2.MessageQueue; +//import apache.rocketmq.v2.Permission; +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import apache.rocketmq.v2.QueryAssignmentResponse; +//import apache.rocketmq.v2.QueryRouteRequest; +//import apache.rocketmq.v2.QueryRouteResponse; +//import io.grpc.Context; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import org.apache.rocketmq.common.protocol.route.QueueData; +//import org.apache.rocketmq.common.protocol.route.TopicRouteData; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.route.MessageQueueView; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +// +//public class RouteService extends AbstractRouteService { +// public RouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { +// super(serviceManager, grpcClientManager); +// } +// +// @Override +// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (queryRouteHook != null) { +// queryRouteHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); +// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); +// List queueDataList = topicRouteData.getQueueDatas(); +// +// List messageQueueList = new ArrayList<>(); +// Endpoints endpoints = request.getEndpoints(); +// Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, endpoints); +// if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { +// future.complete(QueryRouteResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + +// endpoints + " is invalidate")) +// .build()); +// return future; +// } +// for (QueueData queueData : queueDataList) { +// Broker broker = Broker.newBuilder() +// .setName(queueData.getBrokerName()) +// .setId(0) +// .setEndpoints(resEndpoints) +// .build(); +// +// messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); +// } +// QueryRouteResponse response = QueryRouteResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .addAllMessageQueues(messageQueueList) +// .build(); +// future.complete(response); +// } catch (Throwable t) { +// if (TopicRouteHelper.isTopicNotExistError(t)) { +// future.complete(QueryRouteResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) +// .build()); +// } else { +// future.completeExceptionally(t); +// } +// } +// return future; +// } +// +// @Override +// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (queryAssignmentHook != null) { +// queryAssignmentHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// List assignments = new ArrayList<>(); +// List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); +// Endpoints endpoints = request.getEndpoints(); +// Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, endpoints); +// if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { +// future.complete(QueryAssignmentResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + +// endpoints + " is invalidate")) +// .build()); +// return future; +// } +// for (SelectableMessageQueue messageQueue : messageQueueList) { +// Broker broker = Broker.newBuilder() +// .setName(messageQueue.getBrokerName()) +// .setId(0) +// .setEndpoints(resEndpoints) +// .build(); +// +// MessageQueue defaultMessageQueue = MessageQueue.newBuilder() +// .setTopic(request.getTopic()) +// .setId(-1) +// .setPermission(Permission.READ_WRITE) +// .setBroker(broker) +// .build(); +// +// assignments.add(Assignment.newBuilder() +// .setMessageQueue(defaultMessageQueue) +// .build()); +// } +// +// QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() +// .addAllAssignments(assignments) +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build(); +// future.complete(response); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java new file mode 100644 index 0000000000..92cf16b0ad --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java @@ -0,0 +1,139 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.EndTransactionRequest; +//import apache.rocketmq.v2.EndTransactionResponse; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +//import apache.rocketmq.v2.TelemetryCommand; +//import io.grpc.Context; +//import java.util.List; +//import java.util.concurrent.CompletableFuture; +//import java.util.concurrent.ThreadLocalRandom; +//import org.apache.commons.collections.CollectionUtils; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.ForwardProducer; +//import org.apache.rocketmq.proxy.service.transaction.TransactionId; +//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; +//import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; +//import org.apache.rocketmq.remoting.common.RemotingHelper; +// +//public class TransactionService extends BaseService implements TransactionStateChecker { +// +// protected final ChannelManager channelManager; +// protected final ForwardProducer forwardProducer; +// +// private volatile ResponseHook checkTransactionStateHook; +// private volatile ResponseHook endTransactionHook; +// +// public TransactionService(ServiceManager serviceManager, ChannelManager channelManager) { +// super(serviceManager); +// this.forwardProducer = serviceManager.getForwardProducer(); +// this.channelManager = channelManager; +// } +// +// @Override +// public void checkTransactionState(TransactionStateCheckRequest checkData) { +// Context ctx = Context.current(); +// try { +// List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); +// if (CollectionUtils.isEmpty(clientIdList)) { +// return; +// } +// +// String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); +// GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); +// +// String transactionId = checkData.getTransactionId().getProxyTransactionId(); +// MessageExt messageExt = checkData.getMessageExt(); +// Message message = GrpcConverter.buildMessage(messageExt); +// TelemetryCommand response = TelemetryCommand.newBuilder() +// .setRecoverOrphanedTransactionCommand( +// RecoverOrphanedTransactionCommand.newBuilder() +// .setOrphanedTransactionalMessage(message) +// .setTransactionId(transactionId) +// .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, checkData.getBrokerName())) +// .build() +// ).build(); +// +// channel.writeAndFlush(response); +// if (this.checkTransactionStateHook != null) { +// this.checkTransactionStateHook.beforeResponse(ctx, checkData, response, null); +// } +// } catch (Throwable t) { +// if (this.checkTransactionStateHook != null) { +// this.checkTransactionStateHook.beforeResponse(ctx, checkData, null, t); +// } +// } +// } +// +// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (endTransactionHook != null) { +// endTransactionHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// TransactionId handle = TransactionId.decode(request.getTransactionId()); +// String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); +// EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); +// this.forwardProducer.endTransaction(ctx, brokerAddr, requestHeader); +// future.complete(EndTransactionResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build()); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +// +// protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { +// String topic = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// // use topic name as producerGroup +// return GrpcConverter.buildEndTransactionRequestHeader(request, topic); +// } +// +// public ResponseHook getCheckTransactionStateHook() { +// return checkTransactionStateHook; +// } +// +// public void setCheckTransactionStateHook( +// ResponseHook checkTransactionStateHook) { +// this.checkTransactionStateHook = checkTransactionStateHook; +// } +// +// public ResponseHook getEndTransactionHook() { +// return endTransactionHook; +// } +// +// public void setEndTransactionHook( +// ResponseHook endTransactionHook) { +// this.endTransactionHook = endTransactionHook; +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java new file mode 100644 index 0000000000..853bb1df2a --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java @@ -0,0 +1,26 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.SendMessageRequest; +//import io.grpc.Context; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +// +//public interface WriteQueueSelector { +// +// SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request); +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java new file mode 100644 index 0000000000..4f32b0aed2 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java @@ -0,0 +1,76 @@ +///* +// * 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.grpc.v2.service.local; +// +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.Context; +//import io.grpc.stub.StreamObserver; +//import io.netty.channel.Channel; +//import org.apache.rocketmq.broker.BrokerController; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.protocol.RequestCode; +//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; +//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +//import org.apache.rocketmq.remoting.exception.RemotingCommandException; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//public class LocalReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { +// private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// private final ChannelManager channelManager; +// private final BrokerController brokerController; +// +// public LocalReceiveMessageResponseStreamWriter( +// StreamObserver observer, +// ResponseHook hook, +// ChannelManager channelManager, +// BrokerController brokerController, +// ReceiveMessageResultFilter receiveMessageResultFilter) { +// super(observer, hook, receiveMessageResultFilter); +// this.channelManager = channelManager; +// this.brokerController = brokerController; +// } +// +// @Override +// protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, +// Message message) { +// this.changeInvisibleTime(context, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle())); +// } +// +// private void changeInvisibleTime(Context ctx, ReceiveMessageRequest request, ReceiptHandle handle) { +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); +// ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, handle); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); +// command.makeCustomHeaderToNet(); +// try { +// brokerController.getChangeInvisibleTimeProcessor().processRequest(simpleChannelHandlerContext, command); +// } catch (RemotingCommandException e) { +// log.error("ChangeInvisibleTime error when write response", e); +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java new file mode 100644 index 0000000000..2b62522856 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java @@ -0,0 +1,94 @@ +///* +// * 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.grpc.v2.service.local; +// +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import io.grpc.Context; +//import io.netty.channel.Channel; +//import org.apache.rocketmq.broker.BrokerController; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.RequestCode; +//import org.apache.rocketmq.common.protocol.ResponseCode; +//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +//import org.apache.rocketmq.remoting.exception.RemotingCommandException; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//public class LocalReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { +// private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// +// private final ChannelManager channelManager; +// private final BrokerController brokerController; +// +// public LocalReceiveMessageResultFilter(ChannelManager channelManager, BrokerController brokerController, GrpcClientManager grpcClientManager) { +// super(grpcClientManager); +// this.channelManager = channelManager; +// this.brokerController = brokerController; +// } +// +// @Override +// protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { +// ReceiptHandle handle = ReceiptHandle.create(messageExt); +// if (handle == null) { +// return; +// } +// Channel channel = channelManager.createChannel(ctx); +// AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); +// command.makeCustomHeaderToNet(); +// try { +// brokerController.getAckMessageProcessor().processRequest(new SimpleChannelHandlerContext(channel), command); +// } catch (RemotingCommandException e) { +// log.error("AckMessage failed in filterMessage", e); +// } +// } +// +// @Override +// protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, +// int maxAttempts) { +// try { +// ReceiptHandle handle = ReceiptHandle.create(messageExt); +// if (handle == null) { +// return; +// } +// Channel channel = channelManager.createChannel(ctx); +// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); +// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempts); +// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, consumerSendMsgBackRequestHeader); +// command.makeCustomHeaderToNet(); +// RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, command); +// if (response.getCode() == ResponseCode.SUCCESS) { +// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); +// command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, ackMessageRequestHeader); +// command.makeCustomHeaderToNet(); +// brokerController.getAckMessageProcessor().processRequest(simpleChannelHandlerContext, command); +// } +// } catch (Exception e) { +// log.error("ForwardMessageToDLQ failed in filterMessage", e); +// } +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java new file mode 100644 index 0000000000..0553ba39da --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java @@ -0,0 +1,101 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// +//package org.apache.rocketmq.proxy.grpc.v2.service.local; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.SendMessageRequest; +//import com.google.common.hash.Hashing; +//import io.grpc.Context; +//import java.util.Random; +//import java.util.concurrent.atomic.AtomicInteger; +//import org.apache.commons.lang3.StringUtils; +//import org.apache.rocketmq.broker.topic.TopicConfigManager; +//import org.apache.rocketmq.common.TopicConfig; +//import org.apache.rocketmq.common.constant.LoggerName; +//import org.apache.rocketmq.common.message.MessageQueue; +//import org.apache.rocketmq.logging.InternalLogger; +//import org.apache.rocketmq.logging.InternalLoggerFactory; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultWriteQueueSelector; +// +//public class LocalWriteQueueSelector extends DefaultWriteQueueSelector { +// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); +// private final String brokerName; +// private final AtomicInteger queueIndex; +// private final TopicConfigManager topicConfigManager; +// +// public LocalWriteQueueSelector(String brokerName, TopicConfigManager topicConfigManager, TopicRouteService topicRouteService) { +// super(topicRouteService); +// this.brokerName = brokerName; +// this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); +// this.topicConfigManager = topicConfigManager; +// } +// +// @Override +// public SelectableMessageQueue selectQueue( +// Context ctx, +// SendMessageRequest request +// ) { +// try { +// if (request.getMessagesCount() <= 0) { +// throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); +// } +// Message message = request.getMessages(0); +// String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); +// String shardingKey = null; +// if (request.getMessagesCount() == 1) { +// shardingKey = message.getSystemProperties().getMessageGroup(); +// } +// SelectableMessageQueue targetMessageQueue; +// if (StringUtils.isNotEmpty(shardingKey)) { +// // With shardingKey +// targetMessageQueue = selectOrderQueue(topic, shardingKey); +// } else { +// targetMessageQueue = selectNormalQueue(topic); +// } +// return targetMessageQueue; +// } catch (Exception e) { +// log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); +// return null; +// } +// } +// +// protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { +// TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); +// if (topicConfig == null) { +// throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); +// } +// int selectQueueId = queueIndex.getAndIncrement() % topicConfig.getWriteQueueNums(); +// MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); +// return new SelectableMessageQueue(mq, null); +// } +// +// protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { +// TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); +// if (topicConfig == null) { +// throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); +// } +// int selectQueueId = Hashing.consistentHash(shardingKey.hashCode(), topicConfig.getWriteQueueNums()); +// MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); +// return new SelectableMessageQueue(mq, null); +// } +//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java new file mode 100644 index 0000000000..2be0fedb23 --- /dev/null +++ b/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java @@ -0,0 +1,175 @@ +///* +// * 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.grpc.v2.service.local; +// +//import apache.rocketmq.v2.Address; +//import apache.rocketmq.v2.AddressScheme; +//import apache.rocketmq.v2.Assignment; +//import apache.rocketmq.v2.Broker; +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Endpoints; +//import apache.rocketmq.v2.MessageQueue; +//import apache.rocketmq.v2.Permission; +//import apache.rocketmq.v2.QueryAssignmentRequest; +//import apache.rocketmq.v2.QueryAssignmentResponse; +//import apache.rocketmq.v2.QueryRouteRequest; +//import apache.rocketmq.v2.QueryRouteResponse; +//import com.google.common.net.HostAndPort; +//import io.grpc.Context; +//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.common.protocol.route.BrokerData; +//import org.apache.rocketmq.common.protocol.route.QueueData; +//import org.apache.rocketmq.common.protocol.route.TopicRouteData; +//import org.apache.rocketmq.proxy.config.ConfigurationManager; +//import org.apache.rocketmq.proxy.service.ServiceManager; +//import org.apache.rocketmq.proxy.service.route.MessageQueueView; +//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +//import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +// +//public class RouteService extends AbstractRouteService { +// public RouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { +// super(serviceManager, grpcClientManager); +// } +// +// @Override +// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (queryRouteHook != null) { +// queryRouteHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); +// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); +// List queueDataList = topicRouteData.getQueueDatas(); +// List brokerDataList = topicRouteData.getBrokerDatas(); +// +// List messageQueueList = new ArrayList<>(); +// Map> brokerMap = buildBrokerMap(brokerDataList); +// +// for (QueueData queueData : queueDataList) { +// String brokerName = queueData.getBrokerName(); +// Map brokerIdMap = brokerMap.get(brokerName); +// if (brokerIdMap == null) { +// break; +// } +// for (Broker broker : brokerIdMap.values()) { +// messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); +// } +// } +// +// QueryRouteResponse response = QueryRouteResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .addAllMessageQueues(messageQueueList) +// .build(); +// future.complete(response); +// } catch (Throwable t) { +// if (TopicRouteHelper.isTopicNotExistError(t)) { +// future.complete(QueryRouteResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) +// .build()); +// } else { +// future.completeExceptionally(t); +// } +// } +// return future; +// } +// +// @Override +// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { +// CompletableFuture future = new CompletableFuture<>(); +// future.whenComplete((response, throwable) -> { +// if (queryAssignmentHook != null) { +// queryAssignmentHook.beforeResponse(ctx, request, response, throwable); +// } +// }); +// +// try { +// List assignments = new ArrayList<>(); +// List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); +// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); +// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); +// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); +// Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); +// for (SelectableMessageQueue messageQueue : messageQueueList) { +// Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); +// if (brokerIdMap != null) { +// Broker broker = brokerIdMap.get(0L); +// +// MessageQueue defaultMessageQueue = MessageQueue.newBuilder() +// .setTopic(request.getTopic()) +// .setId(-1) +// .setPermission(Permission.READ_WRITE) +// .setBroker(broker) +// .build(); +// +// assignments.add(Assignment.newBuilder() +// .setMessageQueue(defaultMessageQueue) +// .build()); +// } +// } +// QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() +// .addAllAssignments(assignments) +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) +// .build(); +// future.complete(response); +// } catch (Throwable t) { +// future.completeExceptionally(t); +// } +// return future; +// } +// +// private Map> buildBrokerMap(List brokerDataList) { +// Map> brokerMap = new HashMap<>(); +// for (BrokerData brokerData : brokerDataList) { +// Map brokerIdMap = new HashMap<>(); +// String brokerName = brokerData.getBrokerName(); +// for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { +// Long brokerId = entry.getKey(); +// HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); +// Broker broker = Broker.newBuilder() +// .setName(brokerName) +// .setId(Math.toIntExact(brokerId)) +// .setEndpoints(Endpoints.newBuilder() +// .setScheme(AddressScheme.IPv4) +// .addAddresses( +// Address.newBuilder() +// .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) +// .setHost(hostAndPort.getHost()) +// ) +// .build()) +// .build(); +// +// brokerIdMap.put(brokerId, broker); +// } +// brokerMap.put(brokerName, brokerIdMap); +// } +// return brokerMap; +// } +//} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java index 13a87b25d1..b1760e52f1 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java @@ -79,17 +79,15 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.proxy.common.TelemetryCommandManager; import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.apache.rocketmq.proxy.connector.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -106,7 +104,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; @RunWith(MockitoJUnitRunner.class) public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { - private LocalGrpcService localGrpcService; + private LocalGrpcActivity localGrpcService; @Mock private SendMessageProcessor sendMessageProcessorMock; @Mock @@ -144,7 +142,7 @@ public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { Mockito.doNothing().when(producerManagerMock).appendProducerChangeListener(Mockito.any(ProducerChangeListener.class)); Mockito.when(brokerControllerMock.getConsumerManager()).thenReturn(consumerManagerMock); Mockito.when(brokerControllerMock.getProducerManager()).thenReturn(producerManagerMock); - localGrpcService = new LocalGrpcService(brokerControllerMock, telemetryCommandManager); + localGrpcService = new LocalGrpcActivity(brokerControllerMock, telemetryCommandManager); metadata = new Metadata(); metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java similarity index 79% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java index 0d35cfbe5f..3be07c9518 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/BaseServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java @@ -27,13 +27,13 @@ import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.apache.rocketmq.proxy.connector.ConnectorManager; -import org.apache.rocketmq.proxy.connector.DefaultForwardClient; -import org.apache.rocketmq.proxy.connector.ForwardProducer; -import org.apache.rocketmq.proxy.connector.ForwardReadConsumer; -import org.apache.rocketmq.proxy.connector.ForwardWriteConsumer; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; -import org.apache.rocketmq.proxy.connector.transaction.TransactionHeartbeatRegisterService; +import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.service.DefaultForwardClient; +import org.apache.rocketmq.proxy.service.ForwardProducer; +import org.apache.rocketmq.proxy.service.ForwardReadConsumer; +import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; import org.apache.rocketmq.remoting.common.RemotingUtil; @@ -50,7 +50,7 @@ import static org.mockito.Mockito.when; public abstract class BaseServiceTest extends InitConfigAndLoggerTest { @Mock - protected ConnectorManager connectorManager; + protected ServiceManager serviceManager; @Mock protected DefaultForwardClient defaultClient; @Mock @@ -60,9 +60,9 @@ public abstract class BaseServiceTest extends InitConfigAndLoggerTest { @Mock protected ForwardWriteConsumer writeConsumerClient; @Mock - protected TopicRouteCache topicRouteCache; + protected TopicRouteService topicRouteService; @Mock - protected TransactionHeartbeatRegisterService transactionHeartbeatRegisterService; + protected ClusterTransactionService clusterTransactionService; @Mock protected GrpcClientManager grpcClientManager; @@ -74,12 +74,12 @@ public abstract class BaseServiceTest extends InitConfigAndLoggerTest { @Before public void before() throws Throwable { super.before(); - when(connectorManager.getDefaultForwardClient()).thenReturn(defaultClient); - when(connectorManager.getForwardProducer()).thenReturn(producerClient); - when(connectorManager.getForwardReadConsumer()).thenReturn(readConsumerClient); - when(connectorManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); - when(connectorManager.getTopicRouteCache()).thenReturn(topicRouteCache); - when(connectorManager.getTransactionHeartbeatRegisterService()).thenReturn(transactionHeartbeatRegisterService); + when(serviceManager.getDefaultForwardClient()).thenReturn(defaultClient); + when(serviceManager.getForwardProducer()).thenReturn(producerClient); + when(serviceManager.getForwardReadConsumer()).thenReturn(readConsumerClient); + when(serviceManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); + when(serviceManager.getTopicRouteService()).thenReturn(topicRouteService); + when(serviceManager.getTransactionHeartbeatRegisterService()).thenReturn(clusterTransactionService); initContext(); beforeEach(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java similarity index 95% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java index b8d045dc8c..65cad72e35 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java @@ -52,7 +52,7 @@ import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; import org.junit.Test; @@ -80,12 +80,12 @@ public class ConsumerServiceTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { - consumerService = new ConsumerService(this.connectorManager, this.grpcClientManager); + consumerService = new ConsumerService(this.serviceManager, this.grpcClientManager); consumerService.start(); - receiveMessageResultFilter = new DefaultReceiveMessageResultFilter(producerClient, writeConsumerClient, grpcClientManager, topicRouteCache); + receiveMessageResultFilter = new DefaultReceiveMessageResultFilter(producerClient, writeConsumerClient, grpcClientManager, topicRouteService); consumerService.setReceiveMessageWriterBuilder((observer, hook) -> - new DefaultReceiveMessageResponseStreamWriter(observer, hook, writeConsumerClient, topicRouteCache, receiveMessageResultFilter)); + new DefaultReceiveMessageResponseStreamWriter(observer, hook, writeConsumerClient, topicRouteService, receiveMessageResultFilter)); consumerService.setReadQueueSelector(readQueueSelector); } @@ -110,7 +110,7 @@ public class ConsumerServiceTest extends BaseServiceTest { PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())) .thenReturn(CompletableFuture.completedFuture(new AckResult())); @@ -168,7 +168,7 @@ public class ConsumerServiceTest extends BaseServiceTest { PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) .thenReturn(CompletableFuture.completedFuture(popResult)); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); ArgumentCaptor sendMsgBackRequestHeaderArgumentCaptor = ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), sendMsgBackRequestHeaderArgumentCaptor.capture(), any())) @@ -207,7 +207,7 @@ public class ConsumerServiceTest extends BaseServiceTest { @Test public void testAckMessage() throws Exception { - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); @@ -239,7 +239,7 @@ public class ConsumerServiceTest extends BaseServiceTest { ackResult.setExtraInfo(receiptHandle.encode()); when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), anyString(), headerArgumentCaptor.capture())) .thenReturn(CompletableFuture.completedFuture(ackResult)); - when(topicRouteCache.getBrokerAddr(anyString())).thenReturn("brokerAddr"); + when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); Settings clientSettings = createClientSettings(3); when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java similarity index 91% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java index b7436d29bc..231cb821e4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java @@ -21,7 +21,7 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import io.grpc.Context; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.junit.Test; import static org.junit.Assert.assertNull; @@ -46,10 +46,10 @@ public class DefaultReadQueueSelectorTest extends BaseServiceTest { SelectableMessageQueue messageQueue2 = new SelectableMessageQueue( new MessageQueue("oneReadBroker", "brokerName", 0), "brokerAddr1"); - when(topicRouteCache.selectReadBrokerByName(eq("readBrokerTopicByName"), anyString())).thenReturn(messageQueue1); - when(topicRouteCache.selectOneReadBroker(eq("oneReadBroker"), isNull())).thenReturn(messageQueue2); + when(topicRouteService.selectReadBrokerByName(eq("readBrokerTopicByName"), anyString())).thenReturn(messageQueue1); + when(topicRouteService.selectOneReadBroker(eq("oneReadBroker"), isNull())).thenReturn(messageQueue2); - ReadQueueSelector readQueueSelector = new DefaultReadQueueSelector(topicRouteCache); + ReadQueueSelector readQueueSelector = new DefaultReadQueueSelector(topicRouteService); { PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java similarity index 92% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java index 013814cc45..d5922a039d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java @@ -24,7 +24,7 @@ import com.google.protobuf.ByteString; import io.grpc.Context; import java.nio.charset.StandardCharsets; import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -39,13 +39,13 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { SelectableMessageQueue queue = new SelectableMessageQueue( new MessageQueue("topic", "selectOrderQueue", 0), "selectOrderQueueAddr"); - when(topicRouteCache.selectOneWriteQueueByKey(anyString(), anyString())) + when(topicRouteService.selectOneWriteQueueByKey(anyString(), anyString())) .thenReturn(queue); queue = new SelectableMessageQueue( new MessageQueue("topic", "selectNormalQueue", 0), "selectNormalQueueAddr"); - when(topicRouteCache.selectOneWriteQueue(anyString(), isNull())) + when(topicRouteService.selectOneWriteQueue(anyString(), isNull())) .thenReturn(queue); } @@ -64,7 +64,7 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteService); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); assertEquals("selectOrderQueue", queue.getBrokerName()); @@ -85,7 +85,7 @@ public class DefaultWriteQueueSelectorTest extends BaseServiceTest { .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) .build()) .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteCache); + WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteService); SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); assertEquals("selectNormalQueue", queue.getBrokerName()); diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java new file mode 100644 index 0000000000..870fb0b88a --- /dev/null +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java @@ -0,0 +1,142 @@ +///* +// * 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.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.ClientType; +//import apache.rocketmq.v2.FilterExpression; +//import apache.rocketmq.v2.FilterType; +//import apache.rocketmq.v2.HeartbeatRequest; +//import apache.rocketmq.v2.NotifyClientTerminationRequest; +//import apache.rocketmq.v2.Publishing; +//import apache.rocketmq.v2.Resource; +//import apache.rocketmq.v2.Settings; +//import apache.rocketmq.v2.Subscription; +//import apache.rocketmq.v2.SubscriptionEntry; +//import io.grpc.Context; +//import io.netty.channel.Channel; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.Executors; +//import org.apache.rocketmq.broker.client.ClientChannelInfo; +//import org.apache.rocketmq.broker.client.ConsumerGroupInfo; +//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +//import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +//import org.apache.rocketmq.remoting.protocol.LanguageCode; +//import org.junit.Test; +// +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertNotNull; +//import static org.junit.Assert.assertNull; +//import static org.junit.Assert.assertTrue; +//import static org.mockito.ArgumentMatchers.anyString; +//import static org.mockito.Mockito.when; +// +//public class ForwardClientServiceTest extends BaseServiceTest { +// +// private ChannelManager channelManager = new ChannelManager(); +// private TelemetryCommandManager telemetryCommandManager = new TelemetryCommandManager(); +// private ForwardClientService clientService; +// +// @Override +// public void beforeEach() throws Throwable { +// clientService = new ForwardClientService( +// this.serviceManager, +// Executors.newSingleThreadScheduledExecutor(), +// this.channelManager, +// this.grpcClientManager, +// this.telemetryCommandManager); +// clientService.start(); +// } +// +// @Test +// public void testProducerHeartbeat() { +// Settings clientSettings = Settings.newBuilder() +// .setClientType(ClientType.PRODUCER) +// .setPublishing(Publishing.newBuilder() +// .addTopics(Resource.newBuilder() +// .setName("topic1") +// .build()) +// .addTopics(Resource.newBuilder() +// .setName("topic2") +// .build()) +// .build()) +// .build(); +// when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); +// +// clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); +// +// assertEquals(2, clientService.getProducerManager().getGroupChannelTable().size()); +// Channel channel = clientService.getProducerManager().findChannel(CLIENT_ID); +// assertNotNull(channel); +// assertTrue(channel instanceof GrpcClientChannel); +// +// clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder().build()); +// assertTrue(clientService.getProducerManager().getGroupChannelTable().isEmpty()); +// } +// +// @Test +// public void testConsumerHeartbeat() { +// List subscriptionEntryList = new ArrayList<>(); +// subscriptionEntryList.add(SubscriptionEntry.newBuilder() +// .setTopic(Resource.newBuilder() +// .setName("topic") +// .build()) +// .setExpression(FilterExpression.newBuilder() +// .setExpression("*") +// .setType(FilterType.TAG) +// .build()) +// .build()); +// +// Settings clientSettings = Settings.newBuilder() +// .setClientType(ClientType.PUSH_CONSUMER) +// .setSubscription(Subscription.newBuilder() +// .addAllSubscriptions(subscriptionEntryList) +// .build()) +// .build(); +// when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); +// +// clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() +// .setGroup(Resource.newBuilder() +// .setName("consumerGroup") +// .build()) +// .build()); +// +// ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", CLIENT_ID); +// assertNotNull(clientChannelInfo); +// assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); +// assertEquals(CLIENT_ID, clientChannelInfo.getClientId()); +// assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); +// ConsumerGroupInfo consumerGroupInfo = clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup"); +// assertEquals(MessageModel.CLUSTERING, consumerGroupInfo.getMessageModel()); +// assertEquals(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, consumerGroupInfo.getConsumeFromWhere()); +// assertEquals(ConsumeType.CONSUME_PASSIVELY, consumerGroupInfo.getConsumeType()); +// assertEquals("TAG", consumerGroupInfo.getSubscriptionTable().get("topic").getExpressionType()); +// assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); +// +// +// clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder() +// .setGroup(Resource.newBuilder() +// .setName("consumerGroup") +// .build()) +// .build()); +// assertNull(clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup")); +// } +//} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java similarity index 97% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java index 2b205e2298..68344d6899 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java @@ -30,7 +30,7 @@ import java.util.concurrent.ExecutionException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; import org.junit.Test; @@ -62,7 +62,7 @@ public class ProducerServiceTest extends BaseServiceTest { @Override public void beforeEach() throws Throwable { - producerService = new ProducerService(this.connectorManager); + producerService = new ProducerService(this.serviceManager); producerService.start(); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java similarity index 96% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java index 65c0889a67..7cea2646cf 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java @@ -41,7 +41,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; import org.junit.Test; @@ -105,12 +105,12 @@ public class RouteServiceTest extends BaseServiceTest { routeData.setBrokerDatas(brokerDataList); routeData.setQueueDatas(queueDataList); - MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); - when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); + MessageQueueView messageQueueView = new MessageQueueView("topic", routeData); + when(this.topicRouteService.getAllMessageQueueView("topic")).thenReturn(messageQueueView); - when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + when(this.topicRouteService.getAllMessageQueueView("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); - routeService = new RouteService(this.connectorManager, this.grpcClientManager); + routeService = new RouteService(this.serviceManager, this.grpcClientManager); routeService.start(); } diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java new file mode 100644 index 0000000000..f8f647cb01 --- /dev/null +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java @@ -0,0 +1,104 @@ +///* +// * Licensed to the Apache Software Foundation (ASF) under one or more +// * contributor license agreements. See the NOTICE file distributed with +// * this work for additional information regarding copyright ownership. +// * The ASF licenses this file to You under the Apache License, Version 2.0 +// * (the "License"); you may not use this file except in compliance with +// * the License. You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +//package org.apache.rocketmq.proxy.grpc.v2.service.cluster; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.EndTransactionRequest; +//import apache.rocketmq.v2.EndTransactionResponse; +//import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; +//import apache.rocketmq.v2.TelemetryCommand; +//import io.grpc.Context; +//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.service.transaction.TransactionId; +//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; +//import org.apache.rocketmq.remoting.common.RemotingHelper; +//import org.assertj.core.util.Lists; +//import org.junit.Test; +//import org.mockito.ArgumentCaptor; +//import org.mockito.Mock; +// +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertTrue; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.anyString; +//import static org.mockito.Mockito.doNothing; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.when; +// +//public class TransactionServiceTest extends BaseServiceTest { +// +// private TransactionService transactionService; +// @Mock +// private ChannelManager channelManager; +// +// @Override +// public void beforeEach() throws Throwable { +// transactionService = new TransactionService(this.serviceManager, this.channelManager); +// } +// +// @Test +// public void testCheckTransactionState() { +// GrpcClientChannel channel = mock(GrpcClientChannel.class); +// +// when(channelManager.getClientIdList(anyString())).thenReturn(Lists.newArrayList("clientId")); +// when(channelManager.getChannel(anyString(), any())).thenReturn(channel); +// ArgumentCaptor flushDataCaptor = ArgumentCaptor.forClass(Object.class); +// when(channel.writeAndFlush(flushDataCaptor.capture())).thenReturn(null); +// +// TransactionId transactionId = TransactionId.genByBrokerTransactionId( +// RemotingHelper.string2SocketAddress("127.0.0.1:8080"), +// "71F99B78B6E261357FA259CCA6456118", 1234, 5678); +// transactionService.checkTransactionState(new TransactionStateCheckRequest( +// "group", +// 1L, +// 2L, +// "msgId", +// transactionId, +// "brokerName", +// createMessageExt("msgId", "msgId") +// )); +// +// Object flushData = flushDataCaptor.getValue(); +// assertTrue(flushData instanceof TelemetryCommand); +// TelemetryCommand response = (TelemetryCommand) flushData; +// RecoverOrphanedTransactionCommand command = response.getRecoverOrphanedTransactionCommand(); +// assertEquals(transactionId.getProxyTransactionId(), command.getTransactionId()); +// assertEquals("brokerName", command.getMessageQueue().getBroker().getName()); +// } +// +// @Test +// public void testEndTransaction() throws Exception { +// TransactionId transactionId = TransactionId.genByBrokerTransactionId( +// RemotingHelper.string2SocketAddress("127.0.0.1:8080"), +// "71F99B78B6E261357FA259CCA6456118", 1234, 5678); +// ArgumentCaptor brokerAddrCaptor = ArgumentCaptor.forClass(String.class); +// ArgumentCaptor headerCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); +// doNothing().when(producerClient) +// .endTransaction(any(), brokerAddrCaptor.capture(), headerCaptor.capture()); +// +// EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() +// .setTransactionId(transactionId.getProxyTransactionId()) +// .build() +// ).get(); +// +// assertEquals(Code.OK, response.getStatus().getCode()); +// assertEquals(transactionId.getBrokerTransactionId(), headerCaptor.getValue().getTransactionId()); +// assertEquals("127.0.0.1:8080", brokerAddrCaptor.getValue()); +// } +//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java new file mode 100644 index 0000000000..4ef59dcdc1 --- /dev/null +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java @@ -0,0 +1,135 @@ +///* +// * 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.grpc.v2.service.local; +// +//import apache.rocketmq.v2.FilterExpression; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.Settings; +//import io.grpc.Context; +//import java.net.InetSocketAddress; +//import java.nio.charset.StandardCharsets; +//import java.util.ArrayList; +//import java.util.List; +//import org.apache.rocketmq.broker.BrokerController; +//import org.apache.rocketmq.broker.processor.AckMessageProcessor; +//import org.apache.rocketmq.broker.processor.SendMessageProcessor; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.message.MessageConst; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.common.protocol.RequestCode; +//import org.apache.rocketmq.common.protocol.ResponseCode; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.channel.SimpleChannel; +//import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; +//import org.apache.rocketmq.remoting.exception.RemotingCommandException; +//import org.apache.rocketmq.remoting.protocol.RemotingCommand; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.mockito.Mock; +//import org.mockito.Mockito; +//import org.mockito.junit.MockitoJUnitRunner; +// +//@RunWith(MockitoJUnitRunner.class) +//public class LocalPopMessageResultFilterTest extends InitConfigAndLoggerTest { +// @Mock +// private ChannelManager channelManagerMock; +// @Mock +// private BrokerController brokerControllerMock; +// @Mock +// private GrpcClientManager grpcClientManagerMock; +// @Mock +// private AckMessageProcessor ackMessageProcessorMock; +// @Mock +// private SendMessageProcessor sendMessageProcessorMock; +// +// private String topic = "topic"; +// +// @Test +// public void testFilterMessageWhenNotMatch() throws RemotingCommandException { +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); +// Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); +// Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); +// Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); +// Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); +// List messageExtList = new ArrayList<>(); +// MessageExt messageExt = new MessageExt(); +// messageExt.setTopic(topic); +// messageExt.setQueueOffset(0L); +// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); +// messageExt.putUserProperty("key", "value"); +// messageExt.setTags("b"); +// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() +// .startOffset(0L) +// .retrieveTime(0L) +// .invisibleTime(1000L) +// .nextVisibleTime(1000L) +// .reviveQueueId(0) +// .topicType("0") +// .brokerName("brokerName") +// .queueId(0) +// .offset(0L) +// .build().encode()); +// messageExtList.add(messageExt); +// LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); +// localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() +// .setFilterExpression(FilterExpression.newBuilder() +// .setExpression("a").build()).build(), messageExtList); +// Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); +// } +// +// @Test +// public void testFilterMessageWhenDLQ() throws RemotingCommandException { +// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); +// Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); +// Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); +// Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); +// Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); +// Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); +// Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); +// List messageExtList = new ArrayList<>(); +// MessageExt messageExt = new MessageExt(); +// messageExt.setTopic(topic); +// messageExt.setQueueOffset(0L); +// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); +// messageExt.putUserProperty("key", "value"); +// messageExt.setTags("a"); +// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() +// .startOffset(0L) +// .retrieveTime(0L) +// .invisibleTime(1000L) +// .nextVisibleTime(1000L) +// .reviveQueueId(0) +// .topicType("0") +// .brokerName("brokerName") +// .queueId(0) +// .offset(0L) +// .build().encode()); +// messageExtList.add(messageExt); +// LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); +// localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() +// .setFilterExpression(FilterExpression.newBuilder() +// .setExpression("a").build()).build(), messageExtList); +// Mockito.verify(sendMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK)); +// Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); +// } +//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java new file mode 100644 index 0000000000..d9ec53eb43 --- /dev/null +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java @@ -0,0 +1,170 @@ +///* +// * 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.grpc.v2.service.local; +// +//import apache.rocketmq.v2.Code; +//import apache.rocketmq.v2.Message; +//import apache.rocketmq.v2.ReceiveMessageRequest; +//import apache.rocketmq.v2.ReceiveMessageResponse; +//import io.grpc.Context; +//import io.grpc.Status; +//import io.grpc.StatusRuntimeException; +//import io.grpc.stub.ServerCallStreamObserver; +//import java.net.InetSocketAddress; +//import java.nio.charset.StandardCharsets; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.concurrent.atomic.AtomicInteger; +//import org.apache.rocketmq.broker.BrokerController; +//import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; +//import org.apache.rocketmq.client.consumer.PopStatus; +//import org.apache.rocketmq.common.consumer.ReceiptHandle; +//import org.apache.rocketmq.common.message.MessageConst; +//import org.apache.rocketmq.common.message.MessageExt; +//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; +//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; +//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; +//import org.apache.rocketmq.remoting.exception.RemotingCommandException; +//import org.junit.Before; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.mockito.ArgumentCaptor; +//import org.mockito.Mock; +//import org.mockito.Mockito; +//import org.mockito.invocation.InvocationOnMock; +//import org.mockito.junit.MockitoJUnitRunner; +//import org.mockito.stubbing.Answer; +// +//import static org.assertj.core.api.Assertions.assertThat; +// +//@RunWith(MockitoJUnitRunner.class) +//public class LocalReceiveMessageResponseStreamWriterTest { +// @Mock +// private ServerCallStreamObserver streamObserverMock; +// @Mock +// private ChannelManager channelManagerMock; +// @Mock +// private BrokerController brokerControllerMock; +// @Mock +// private ReceiveMessageResultFilter receiveMessageResultFilterMock; +// @Mock +// private ChangeInvisibleTimeProcessor changeInvisibleTimeProcessorMock; +// +// private LocalReceiveMessageResponseStreamWriter localReceiveMessageResponseStreamWriter; +// +// @Before +// public void setup() { +// Mockito.when(receiveMessageResultFilterMock.filterMessage(Mockito.any(), Mockito.any(), Mockito.anyList())).thenAnswer((Answer>) invocation -> { +// List messageList = new ArrayList<>(); +// List messageExtList = invocation.getArgument(2); +// for (MessageExt messageExt : messageExtList) { +// messageList.add(GrpcConverter.buildMessage(messageExt)); +// } +// return messageList; +// }); +// localReceiveMessageResponseStreamWriter +// = new LocalReceiveMessageResponseStreamWriter(streamObserverMock, null, channelManagerMock, brokerControllerMock, receiveMessageResultFilterMock); +// } +// +// @Test +// public void testWrite() { +// MessageExt messageExt = new MessageExt(); +// messageExt.setTopic("topic"); +// messageExt.setQueueOffset(0L); +// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); +// messageExt.putUserProperty("key", "value"); +// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() +// .startOffset(0L) +// .retrieveTime(0L) +// .invisibleTime(1000L) +// .nextVisibleTime(1000L) +// .reviveQueueId(0) +// .topicType("0") +// .brokerName("brokerName") +// .queueId(0) +// .offset(0L) +// .build().encode()); +// messageExt.putUserProperty("key", "value"); +// List messageExtList = new ArrayList<>(); +// messageExtList.add(messageExt); +// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); +// ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); +// Mockito.verify(streamObserverMock, Mockito.times(2)).onNext(argument.capture()); +// assertThat(argument.getAllValues().get(0)).isEqualTo(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build()); +// assertThat(argument.getAllValues().get(1)).isEqualTo(ReceiveMessageResponse.newBuilder() +// .setMessage(GrpcConverter.buildMessage(messageExt)).build()); +// } +// +// @Test +// public void testWriteWhenNoMessage() { +// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, new ArrayList<>()); +// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")).build())); +// } +// +// @Test +// public void testWriteWhenCancel() throws RemotingCommandException { +// AtomicInteger onNextCallTimes = new AtomicInteger(0); +// Mockito.doAnswer(mock -> { +// if (onNextCallTimes.get() <=0) { +// onNextCallTimes.incrementAndGet(); +// return null; +// } +// throw new StatusRuntimeException(Status.CANCELLED); +// }).when(streamObserverMock).onNext(Mockito.any()); +// Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); +// MessageExt messageExt = new MessageExt(); +// messageExt.setTopic("topic"); +// messageExt.setQueueOffset(0L); +// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); +// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); +// messageExt.putUserProperty("key", "value"); +// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() +// .startOffset(0L) +// .retrieveTime(0L) +// .invisibleTime(1000L) +// .nextVisibleTime(1000L) +// .reviveQueueId(0) +// .topicType("0") +// .brokerName("brokerName") +// .queueId(0) +// .offset(0L) +// .build().encode()); +// messageExt.putUserProperty("key", "value"); +// List messageExtList = new ArrayList<>(); +// messageExtList.add(messageExt); +// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); +// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build())); +// Mockito.verify(changeInvisibleTimeProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.any()); +// } +// +// @Test +// public void testWriteError() { +// String info = "error"; +// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), new ProxyException(Code.ILLEGAL_MESSAGE, info)); +// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() +// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_MESSAGE, info)).build())); +// } +//} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java similarity index 98% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java index bacf434fd5..4e6a871928 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java @@ -24,7 +24,7 @@ import apache.rocketmq.v2.SystemProperties; import io.grpc.Context; import org.apache.rocketmq.broker.topic.TopicConfigManager; import org.apache.rocketmq.common.TopicConfig; -import org.apache.rocketmq.proxy.connector.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java similarity index 89% rename from proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java rename to proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java index 25078d4a89..d7c8bee76f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/service/local/RouteServiceTest.java +++ b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java @@ -38,7 +38,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseServiceTest; import org.junit.Test; @@ -60,7 +60,7 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testLocalModeQueryRoute() throws Exception { - RouteService routeService = new RouteService(this.connectorManager, this.grpcClientManager); + RouteService routeService = new RouteService(this.serviceManager, this.grpcClientManager); routeService.start(); when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); @@ -79,7 +79,7 @@ public class RouteServiceTest extends BaseServiceTest { @Test public void testLocalModeQueryAssignment() throws Exception { - RouteService routeService = new RouteService(this.connectorManager, this.grpcClientManager); + RouteService routeService = new RouteService(this.serviceManager, this.grpcClientManager); routeService.start(); when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); @@ -124,9 +124,9 @@ public class RouteServiceTest extends BaseServiceTest { routeData.setBrokerDatas(brokerDataList); routeData.setQueueDatas(queueDataList); - MessageQueueWrapper messageQueueWrapper = new MessageQueueWrapper("topic", routeData); - when(this.topicRouteCache.getMessageQueue("topic")).thenReturn(messageQueueWrapper); + MessageQueueView messageQueueView = new MessageQueueView("topic", routeData); + when(this.topicRouteService.getAllMessageQueueView("topic")).thenReturn(messageQueueView); - when(this.topicRouteCache.getMessageQueue("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + when(this.topicRouteService.getAllMessageQueueView("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java b/proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java similarity index 66% rename from proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java rename to proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java index 0cd627411a..b6b81eb2d8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/connector/ForwardClientManagerTest.java +++ b/proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java @@ -15,9 +15,9 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.connector; +package org.apache.rocketmq.proxy.service; -import org.apache.rocketmq.proxy.connector.transaction.TransactionStateChecker; +import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.junit.Test; @@ -32,23 +32,23 @@ public class ForwardClientManagerTest extends InitConfigAndLoggerTest { ConfigurationManager.getProxyConfig().setNameSrvAddr("127.0.0.1:9876"); TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); - ConnectorManager connectorManager = new ConnectorManager(mockedTransactionStateChecker); - connectorManager.start(); + ServiceManager serviceManager = new ServiceManager(mockedTransactionStateChecker); + serviceManager.start(); - assertThat(connectorManager.getDefaultForwardClient()).isNotNull(); - assertThat(connectorManager.getDefaultForwardClient().getClientNum()) + assertThat(serviceManager.getDefaultForwardClient()).isNotNull(); + assertThat(serviceManager.getDefaultForwardClient().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultForwardClientNum()); - assertThat(connectorManager.getForwardProducer()).isNotNull(); - assertThat(connectorManager.getForwardProducer().getClientNum()) + assertThat(serviceManager.getForwardProducer()).isNotNull(); + assertThat(serviceManager.getForwardProducer().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getForwardProducerNum()); - assertThat(connectorManager.getForwardReadConsumer()).isNotNull(); - assertThat(connectorManager.getForwardReadConsumer().getClientNum()) + assertThat(serviceManager.getForwardReadConsumer()).isNotNull(); + assertThat(serviceManager.getForwardReadConsumer().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); - assertThat(connectorManager.getForwardWriteConsumer()).isNotNull(); - assertThat(connectorManager.getForwardWriteConsumer().getClientNum()) + assertThat(serviceManager.getForwardWriteConsumer()).isNotNull(); + assertThat(serviceManager.getForwardWriteConsumer().getClientNum()) .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); } diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java index 7d614cffb5..c2f7b308d0 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java @@ -106,7 +106,7 @@ public class RemotingCommand { return cmd; } - private static void setCmdVersion(RemotingCommand cmd) { + protected static void setCmdVersion(RemotingCommand cmd) { if (configVersion >= 0) { cmd.setVersion(configVersion); } else { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index 3aa510ed0d..e9bbdc14f8 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -23,9 +23,8 @@ import java.time.Duration; import java.util.Map; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.v2.service.ClusterGrpcService; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcForwardService; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; +import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.test.util.MQAdminTestUtils; import org.junit.After; import org.junit.Before; @@ -35,16 +34,18 @@ import static org.awaitility.Awaitility.await; public class ClusterGrpcIT extends GrpcBaseIT { - private GrpcForwardService grpcForwardService; + private ServiceManager serviceManager; + private GrpcMessagingApplication grpcMessagingApplication; @Before public void setUp() throws Exception { super.setUp(); ConfigurationManager.getProxyConfig().setTransactionHeartbeatPeriodSecond(3); - grpcForwardService = new ClusterGrpcService(); - grpcForwardService.start(); - GrpcMessagingProcessor processor = new GrpcMessagingProcessor(grpcForwardService); - setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + serviceManager = ServiceManager.createForClusterMode(); + serviceManager.start(); + grpcMessagingApplication = GrpcMessagingApplication.create(serviceManager); + grpcMessagingApplication.start(); + setUpServer(grpcMessagingApplication, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); await().atMost(Duration.ofSeconds(40)).until(() -> { Map brokerDataMap = MQAdminTestUtils.getCluster(nsAddr).getBrokerAddrTable(); @@ -54,7 +55,8 @@ public class ClusterGrpcIT extends GrpcBaseIT { @After public void tearDown() throws Exception { - grpcForwardService.shutdown(); + serviceManager.shutdown(); + grpcMessagingApplication.shutdown(); shutdown(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index df68948808..954167e79f 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -20,27 +20,31 @@ package org.apache.rocketmq.test.grpc.v2; import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteResponse; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingProcessor; -import org.apache.rocketmq.proxy.grpc.v2.service.LocalGrpcService; +import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; +import org.apache.rocketmq.proxy.service.ServiceManager; import org.junit.After; import org.junit.Before; import org.junit.Test; public class LocalGrpcIT extends GrpcBaseIT { - private LocalGrpcService localGrpcService; + + private ServiceManager serviceManager; + private GrpcMessagingApplication grpcMessagingApplication; @Before public void setUp() throws Exception { super.setUp(); - localGrpcService = new LocalGrpcService(brokerController1); - localGrpcService.start(); - GrpcMessagingProcessor processor = new GrpcMessagingProcessor(localGrpcService); - setUpServer(processor, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); + serviceManager = ServiceManager.createForClusterMode(); + serviceManager.start(); + grpcMessagingApplication = GrpcMessagingApplication.create(serviceManager); + grpcMessagingApplication.start(); + setUpServer(grpcMessagingApplication, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); } @After public void clean() throws Exception { - localGrpcService.shutdown(); + serviceManager.shutdown(); + grpcMessagingApplication.shutdown(); shutdown(); } From 48a46f0f88398a9177fba805ad6545739f44aad8 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 17 May 2022 16:16:54 +0800 Subject: [PATCH 175/338] refactor: [ISSUE #3949] v2 support --- .../apache/rocketmq/common/BrokerConfig.java | 2 +- .../apache/rocketmq/proxy/ProxyStartup.java | 24 +- .../apache/rocketmq/proxy/common/Address.java | 18 + .../proxy/common/ProxyExceptionCode.java | 3 +- .../proxy/common/utils/FutureUtils.java | 39 ++ .../rocketmq/proxy/config/ProxyConfig.java | 190 +++++---- .../grpc/v2/AbstractMessingActivity.java | 2 +- .../grpc/v2/DefaultGrpcMessingActivity.java | 30 +- .../grpc/v2/GrpcMessagingApplication.java | 366 ++++++++++++++---- .../grpc/v2/channel/GrpcChannelManager.java | 75 +++- .../grpc/v2/channel/GrpcClientChannel.java | 5 +- .../proxy/grpc/v2/client/ClientActivity.java | 55 +-- .../proxy/grpc/v2/common/GrpcConverter.java | 5 +- .../proxy/grpc/v2/route/RouteActivity.java | 28 +- .../proxy/processor/ConsumerProcessor.java | 23 +- .../processor/DefaultMessagingProcessor.java | 65 +++- .../proxy/processor/MessagingProcessor.java | 3 +- .../proxy/processor/ProducerProcessor.java | 23 +- .../proxy/processor/TransactionProcessor.java | 16 +- .../proxy/service/ClusterServiceManager.java | 3 - .../service/mqclient/MQClientAPIFactory.java | 6 +- .../service/out/ClusterProxyOutService.java | 11 +- .../service/out/LocalProxyOutService.java | 29 +- .../proxy/service/out/ProxyChannel.java | 4 +- .../proxy/service/out/ProxyOutResult.java | 54 +++ .../proxy/service/out/ProxyOutService.java | 4 +- .../service/route/TopicRouteService.java | 11 +- .../ClusterTransactionService.java | 1 - .../proxy/grpc/v2/BaseActivityTest.java | 82 ++++ .../v2/consumer/AckMessageActivityTest.java | 91 +++++ .../ChangeInvisibleDurationActivityTest.java | 101 +++++ .../consumer/ReceiveMessageActivityTest.java | 118 ++++++ ...eceiveMessageResponseStreamWriterTest.java | 156 ++++++++ .../grpc/v2/route/RouteActivityTest.java | 235 +++++++++++ .../proxy/processor/BaseProcessorTest.java | 8 +- .../processor/ConsumerProcessorTest.java | 3 +- .../processor/ProducerProcessorTest.java | 90 +++++ .../processor/TransactionProcessorTest.java | 81 ++++ .../remoting/netty/NettyClientConfig.java | 13 +- .../rocketmq/test/grpc/v2/ClusterGrpcIT.java | 13 +- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 +- .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 12 +- 42 files changed, 1770 insertions(+), 330 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java 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 df22fb1f8e..edb30b576d 100644 --- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java +++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java @@ -248,7 +248,7 @@ public class BrokerConfig extends BrokerIdentity { * Transaction message check interval. */ @ImportantField - private long transactionCheckInterval = 3 * 1000; + private long transactionCheckInterval = 60 * 1000; /** * Acl feature switch 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 fe09ef38cc..22637f9981 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -37,8 +37,8 @@ import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.GrpcServer; import org.apache.rocketmq.proxy.grpc.GrpcServerBuilder; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; -import org.apache.rocketmq.proxy.service.ServiceManager; -import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.slf4j.LoggerFactory; public class ProxyStartup { @@ -63,11 +63,11 @@ public class ProxyStartup { ThreadPoolExecutor executor = createServerExecutor(); - ServiceManager serviceManager = createServiceManager(null); + MessagingProcessor messagingProcessor = createMessagingProcessor(); // create grpcServer GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor) - .addService(createServiceProcessor(serviceManager)) + .addService(createServiceProcessor(messagingProcessor)) .configInterceptor() .build(); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer); @@ -94,12 +94,12 @@ public class ProxyStartup { log.info(new Date() + " rmq-proxy startup successfully"); } - private static ServiceManager createServiceManager(RPCHook rpcHook) { + private static MessagingProcessor createMessagingProcessor() { String proxyModeStr = ConfigurationManager.getProxyConfig().getProxyMode(); - ServiceManager serviceManager; + MessagingProcessor messagingProcessor; if (ProxyMode.isClusterMode(proxyModeStr)) { - serviceManager = ServiceManager.createForClusterMode(rpcHook); + messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); } else if (ProxyMode.isLocalMode(proxyModeStr)) { BrokerController brokerController = createBrokerController(); StartAndShutdown brokerControllerWrapper = new StartAndShutdown() { @@ -114,16 +114,16 @@ public class ProxyStartup { } }; PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(brokerControllerWrapper); - serviceManager = ServiceManager.createForLocalMode(brokerController, rpcHook); + messagingProcessor = DefaultMessagingProcessor.createForLocalMode(brokerController); } else { throw new IllegalArgumentException("try to start grpc server with wrong mode, use 'local' or 'cluster'"); } - PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(serviceManager); - return serviceManager; + PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(messagingProcessor); + return messagingProcessor; } - private static GrpcMessagingApplication createServiceProcessor(ServiceManager serviceManager) { - GrpcMessagingApplication application = GrpcMessagingApplication.create(serviceManager); + private static GrpcMessagingApplication createServiceProcessor(MessagingProcessor messagingProcessor) { + GrpcMessagingApplication application = GrpcMessagingApplication.create(messagingProcessor); PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(application); return application; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java index 7480fb2fa0..2fc1dab40e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/Address.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.common; import com.google.common.net.HostAndPort; +import java.util.Objects; public class Address { @@ -50,4 +51,21 @@ public class Address { public void setHostAndPort(HostAndPort hostAndPort) { this.hostAndPort = hostAndPort; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Address address = (Address) o; + return addressScheme == address.addressScheme && Objects.equals(hostAndPort, address.hostAndPort); + } + + @Override + public int hashCode() { + return Objects.hash(addressScheme, hostAndPort); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 95b3a93f69..ae056b2168 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -19,5 +19,6 @@ package org.apache.rocketmq.proxy.common; public enum ProxyExceptionCode { FORBIDDEN, RECEIPT_HANDLE_EXPIRED, - INVALID_BROKER_NAME + INVALID_BROKER_NAME, + INVALID_RECEIPT_HANDLE } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java new file mode 100644 index 0000000000..3e3c5623ee --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.common.utils; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; + +public class FutureUtils { + + public static CompletableFuture appendNextFuture(CompletableFuture future, CompletableFuture nextFuture, ExecutorService executor) { + future.whenCompleteAsync((t, throwable) -> { + if (throwable != null) { + nextFuture.completeExceptionally(throwable); + } else { + nextFuture.complete(t); + } + }, executor); + return nextFuture; + } + + public static CompletableFuture addExecutor(CompletableFuture future, ExecutorService executor) { + return appendNextFuture(future, new CompletableFuture<>(), executor); + } +} 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 43a11bab4d..4ccc8bc57f 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 @@ -21,6 +21,7 @@ import org.apache.rocketmq.proxy.ProxyMode; public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; + private static final int PROCESSOR_NUMBER = Runtime.getRuntime().availableProcessors(); /** * configuration for ThreadPoolMonitor @@ -41,9 +42,9 @@ public class ProxyConfig { private String grpcTlsKeyPath = ConfigurationManager.getProxyHome() + "/conf/tls/rocketmq.key"; private String grpcTlsCertPath = ConfigurationManager.getProxyHome() + "/conf/tls/rocketmq.crt"; private int grpcBossLoopNum = 1; - private int grpcWorkerLoopNum = Runtime.getRuntime().availableProcessors() * 2; + private int grpcWorkerLoopNum = PROCESSOR_NUMBER * 2; private boolean enableGrpcEpoll = false; - private int grpcThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2; + private int grpcThreadPoolNums = 16 + PROCESSOR_NUMBER * 2; private int grpcThreadPoolQueueCapacity = 100000; private String brokerConfigPath = ConfigurationManager.getProxyHome() + "/conf/broker.conf"; /** @@ -55,21 +56,28 @@ public class ProxyConfig { private int channelExpiredInSeconds = 60; private int rocketmqMQClientNum = 6; - private double rocketmqMQClientWorkerFactor = 0.2f; - private int forwardConsumerNum = 2; - private double forwardConsumerWorkerFactor = 0.2f; - private int forwardProducerNum = 2; - private double forwardProducerWorkerFactor = 0.2f; - private int defaultForwardClientNum = 2; - private double defaultForwardClientWorkerFactor = 0.2f; + private long grpcProxyOutRequestTimeoutSecond = 5; + private int grpcProducerThreadPoolNums = PROCESSOR_NUMBER; + private int grpcProducerThreadQueueCapacity = 10000; + private int grpcConsumerThreadPoolNums = PROCESSOR_NUMBER; + private int grpcConsumerThreadQueueCapacity = 10000; + private int grpcRouteThreadPoolNums = PROCESSOR_NUMBER; + private int grpcRouteThreadQueueCapacity = 10000; + private int grpcClientManagerThreadPoolNums = PROCESSOR_NUMBER; + private int grpcClientManagerThreadQueueCapacity = 10000; + private int grpcTransactionThreadPoolNums = PROCESSOR_NUMBER; + private int grpcTransactionThreadQueueCapacity = 10000; - private int topicRouteCacheExpiredInSeconds = 20; - private int topicRouteCacheExecutorThreadNum = 3; - private int topicRouteCacheExecutorQueueCapacity = 1000; - private int topicRouteCacheMaxNum = 20000; - private int topicRouteThreadPoolNums = 36; - private int topicRouteThreadPoolQueueCapacity = 50000; + private int producerProcessorThreadPoolNums = PROCESSOR_NUMBER; + private int producerProcessorThreadPoolQueueCapacity = 10000; + private int consumerProcessorThreadPoolNums = PROCESSOR_NUMBER; + private int consumerProcessorThreadPoolQueueCapacity = 10000; + + private int topicRouteServiceCacheExpiredInSeconds = 20; + private int topicRouteServiceCacheMaxNum = 20000; + private int topicRouteServiceThreadPoolNums = PROCESSOR_NUMBER; + private int topicRouteServiceThreadPoolQueueCapacity = 5000; private int transactionHeartbeatThreadPoolNums = 20; private int transactionHeartbeatThreadPoolQueueCapacity = 200; @@ -240,108 +248,156 @@ public class ProxyConfig { this.rocketmqMQClientNum = rocketmqMQClientNum; } - public double getRocketmqMQClientWorkerFactor() { - return rocketmqMQClientWorkerFactor; + public long getGrpcProxyOutRequestTimeoutSecond() { + return grpcProxyOutRequestTimeoutSecond; } - public void setRocketmqMQClientWorkerFactor(double rocketmqMQClientWorkerFactor) { - this.rocketmqMQClientWorkerFactor = rocketmqMQClientWorkerFactor; + public void setGrpcProxyOutRequestTimeoutSecond(long grpcProxyOutRequestTimeoutSecond) { + this.grpcProxyOutRequestTimeoutSecond = grpcProxyOutRequestTimeoutSecond; } - public int getForwardConsumerNum() { - return forwardConsumerNum; + public int getGrpcProducerThreadPoolNums() { + return grpcProducerThreadPoolNums; } - public void setForwardConsumerNum(int forwardConsumerNum) { - this.forwardConsumerNum = forwardConsumerNum; + public void setGrpcProducerThreadPoolNums(int grpcProducerThreadPoolNums) { + this.grpcProducerThreadPoolNums = grpcProducerThreadPoolNums; } - public double getForwardConsumerWorkerFactor() { - return forwardConsumerWorkerFactor; + public int getGrpcProducerThreadQueueCapacity() { + return grpcProducerThreadQueueCapacity; } - public void setForwardConsumerWorkerFactor(double forwardConsumerWorkerFactor) { - this.forwardConsumerWorkerFactor = forwardConsumerWorkerFactor; + public void setGrpcProducerThreadQueueCapacity(int grpcProducerThreadQueueCapacity) { + this.grpcProducerThreadQueueCapacity = grpcProducerThreadQueueCapacity; } - public int getForwardProducerNum() { - return forwardProducerNum; + public int getGrpcConsumerThreadPoolNums() { + return grpcConsumerThreadPoolNums; } - public void setForwardProducerNum(int forwardProducerNum) { - this.forwardProducerNum = forwardProducerNum; + public void setGrpcConsumerThreadPoolNums(int grpcConsumerThreadPoolNums) { + this.grpcConsumerThreadPoolNums = grpcConsumerThreadPoolNums; } - public double getForwardProducerWorkerFactor() { - return forwardProducerWorkerFactor; + public int getGrpcConsumerThreadQueueCapacity() { + return grpcConsumerThreadQueueCapacity; } - public void setForwardProducerWorkerFactor(double forwardProducerWorkerFactor) { - this.forwardProducerWorkerFactor = forwardProducerWorkerFactor; + public void setGrpcConsumerThreadQueueCapacity(int grpcConsumerThreadQueueCapacity) { + this.grpcConsumerThreadQueueCapacity = grpcConsumerThreadQueueCapacity; } - public int getDefaultForwardClientNum() { - return defaultForwardClientNum; + public int getGrpcRouteThreadPoolNums() { + return grpcRouteThreadPoolNums; } - public void setDefaultForwardClientNum(int defaultForwardClientNum) { - this.defaultForwardClientNum = defaultForwardClientNum; + public void setGrpcRouteThreadPoolNums(int grpcRouteThreadPoolNums) { + this.grpcRouteThreadPoolNums = grpcRouteThreadPoolNums; } - public double getDefaultForwardClientWorkerFactor() { - return defaultForwardClientWorkerFactor; + public int getGrpcRouteThreadQueueCapacity() { + return grpcRouteThreadQueueCapacity; } - public void setDefaultForwardClientWorkerFactor(double defaultForwardClientWorkerFactor) { - this.defaultForwardClientWorkerFactor = defaultForwardClientWorkerFactor; + public void setGrpcRouteThreadQueueCapacity(int grpcRouteThreadQueueCapacity) { + this.grpcRouteThreadQueueCapacity = grpcRouteThreadQueueCapacity; } - public int getTopicRouteCacheExpiredInSeconds() { - return topicRouteCacheExpiredInSeconds; + public int getGrpcClientManagerThreadPoolNums() { + return grpcClientManagerThreadPoolNums; } - public void setTopicRouteCacheExpiredInSeconds(int topicRouteCacheExpiredInSeconds) { - this.topicRouteCacheExpiredInSeconds = topicRouteCacheExpiredInSeconds; + public void setGrpcClientManagerThreadPoolNums(int grpcClientManagerThreadPoolNums) { + this.grpcClientManagerThreadPoolNums = grpcClientManagerThreadPoolNums; } - public int getTopicRouteCacheExecutorThreadNum() { - return topicRouteCacheExecutorThreadNum; + public int getGrpcClientManagerThreadQueueCapacity() { + return grpcClientManagerThreadQueueCapacity; } - public void setTopicRouteCacheExecutorThreadNum(int topicRouteCacheExecutorThreadNum) { - this.topicRouteCacheExecutorThreadNum = topicRouteCacheExecutorThreadNum; + public void setGrpcClientManagerThreadQueueCapacity(int grpcClientManagerThreadQueueCapacity) { + this.grpcClientManagerThreadQueueCapacity = grpcClientManagerThreadQueueCapacity; } - public int getTopicRouteCacheExecutorQueueCapacity() { - return topicRouteCacheExecutorQueueCapacity; + public int getGrpcTransactionThreadPoolNums() { + return grpcTransactionThreadPoolNums; } - public void setTopicRouteCacheExecutorQueueCapacity(int topicRouteCacheExecutorQueueCapacity) { - this.topicRouteCacheExecutorQueueCapacity = topicRouteCacheExecutorQueueCapacity; + public void setGrpcTransactionThreadPoolNums(int grpcTransactionThreadPoolNums) { + this.grpcTransactionThreadPoolNums = grpcTransactionThreadPoolNums; } - public int getTopicRouteCacheMaxNum() { - return topicRouteCacheMaxNum; + public int getGrpcTransactionThreadQueueCapacity() { + return grpcTransactionThreadQueueCapacity; } - public void setTopicRouteCacheMaxNum(int topicRouteCacheMaxNum) { - this.topicRouteCacheMaxNum = topicRouteCacheMaxNum; + public void setGrpcTransactionThreadQueueCapacity(int grpcTransactionThreadQueueCapacity) { + this.grpcTransactionThreadQueueCapacity = grpcTransactionThreadQueueCapacity; } - public int getTopicRouteThreadPoolNums() { - return topicRouteThreadPoolNums; + public int getProducerProcessorThreadPoolNums() { + return producerProcessorThreadPoolNums; } - public void setTopicRouteThreadPoolNums(int topicRouteThreadPoolNums) { - this.topicRouteThreadPoolNums = topicRouteThreadPoolNums; + public void setProducerProcessorThreadPoolNums(int producerProcessorThreadPoolNums) { + this.producerProcessorThreadPoolNums = producerProcessorThreadPoolNums; } - public int getTopicRouteThreadPoolQueueCapacity() { - return topicRouteThreadPoolQueueCapacity; + public int getProducerProcessorThreadPoolQueueCapacity() { + return producerProcessorThreadPoolQueueCapacity; } - public void setTopicRouteThreadPoolQueueCapacity(int topicRouteThreadPoolQueueCapacity) { - this.topicRouteThreadPoolQueueCapacity = topicRouteThreadPoolQueueCapacity; + public void setProducerProcessorThreadPoolQueueCapacity(int producerProcessorThreadPoolQueueCapacity) { + this.producerProcessorThreadPoolQueueCapacity = producerProcessorThreadPoolQueueCapacity; + } + + public int getConsumerProcessorThreadPoolNums() { + return consumerProcessorThreadPoolNums; + } + + public void setConsumerProcessorThreadPoolNums(int consumerProcessorThreadPoolNums) { + this.consumerProcessorThreadPoolNums = consumerProcessorThreadPoolNums; + } + + public int getConsumerProcessorThreadPoolQueueCapacity() { + return consumerProcessorThreadPoolQueueCapacity; + } + + public void setConsumerProcessorThreadPoolQueueCapacity(int consumerProcessorThreadPoolQueueCapacity) { + this.consumerProcessorThreadPoolQueueCapacity = consumerProcessorThreadPoolQueueCapacity; + } + + public int getTopicRouteServiceCacheExpiredInSeconds() { + return topicRouteServiceCacheExpiredInSeconds; + } + + public void setTopicRouteServiceCacheExpiredInSeconds(int topicRouteServiceCacheExpiredInSeconds) { + this.topicRouteServiceCacheExpiredInSeconds = topicRouteServiceCacheExpiredInSeconds; + } + + public int getTopicRouteServiceCacheMaxNum() { + return topicRouteServiceCacheMaxNum; + } + + public void setTopicRouteServiceCacheMaxNum(int topicRouteServiceCacheMaxNum) { + this.topicRouteServiceCacheMaxNum = topicRouteServiceCacheMaxNum; + } + + public int getTopicRouteServiceThreadPoolNums() { + return topicRouteServiceThreadPoolNums; + } + + public void setTopicRouteServiceThreadPoolNums(int topicRouteServiceThreadPoolNums) { + this.topicRouteServiceThreadPoolNums = topicRouteServiceThreadPoolNums; + } + + public int getTopicRouteServiceThreadPoolQueueCapacity() { + return topicRouteServiceThreadPoolQueueCapacity; + } + + public void setTopicRouteServiceThreadPoolQueueCapacity(int topicRouteServiceThreadPoolQueueCapacity) { + this.topicRouteServiceThreadPoolQueueCapacity = topicRouteServiceThreadPoolQueueCapacity; } public int getTransactionHeartbeatThreadPoolNums() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 925d36ae37..24ef2f40f1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -37,6 +37,6 @@ public abstract class AbstractMessingActivity { protected ProxyContext createContext(Context ctx) { return ProxyContext.create() .withVal(GrpcContextConstants.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) - .withVal(GrpcContextConstants.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE))); + .withVal(GrpcContextConstants.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 57f5390080..f63ee61816 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -53,14 +53,11 @@ import org.apache.rocketmq.proxy.grpc.v2.producer.ForwardMessageToDLQActivity; import org.apache.rocketmq.proxy.grpc.v2.producer.SendMessageActivity; import org.apache.rocketmq.proxy.grpc.v2.route.RouteActivity; import org.apache.rocketmq.proxy.grpc.v2.transaction.EndTransactionActivity; -import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.ServiceManager; public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ServiceManager serviceManager; private GrpcClientSettingsManager grpcClientSettingsManager; private final ReceiveMessageActivity receiveMessageActivity; @@ -72,26 +69,17 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme private final RouteActivity routeActivity; private final ClientActivity clientActivity; - private final MessagingProcessor messagingProcessor; - - protected DefaultGrpcMessingActivity(ServiceManager serviceManager) { - this.serviceManager = serviceManager; + protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { this.grpcClientSettingsManager = new GrpcClientSettingsManager(); - this.messagingProcessor = new DefaultMessagingProcessor(serviceManager); - - this.receiveMessageActivity = new ReceiveMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.ackMessageActivity = new AckMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.sendMessageActivity = new SendMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.endTransactionActivity = new EndTransactionActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.routeActivity = new RouteActivity(this.messagingProcessor, this.grpcClientSettingsManager); - this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager); - } - - protected void init() { - this.appendStartAndShutdown(serviceManager); + this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, this.grpcClientSettingsManager); + this.ackMessageActivity = new AckMessageActivity(messagingProcessor, this.grpcClientSettingsManager); + this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(messagingProcessor, this.grpcClientSettingsManager); + this.sendMessageActivity = new SendMessageActivity(messagingProcessor, this.grpcClientSettingsManager); + this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(messagingProcessor, this.grpcClientSettingsManager); + this.endTransactionActivity = new EndTransactionActivity(messagingProcessor, this.grpcClientSettingsManager); + this.routeActivity = new RouteActivity(messagingProcessor, this.grpcClientSettingsManager); + this.clientActivity = new ClientActivity(messagingProcessor, this.grpcClientSettingsManager); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 6449259802..85c0059c13 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -21,6 +21,7 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.Code; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; @@ -43,167 +44,360 @@ import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; -import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServiceImplBase implements StartAndShutdown { private final GrpcMessingActivity grpcMessingActivity; + protected ThreadPoolExecutor routeThreadPoolExecutor; + protected ThreadPoolExecutor producerThreadPoolExecutor; + protected ThreadPoolExecutor consumerThreadPoolExecutor; + protected ThreadPoolExecutor clientManagerThreadPoolExecutor; + protected ThreadPoolExecutor transactionThreadPoolExecutor; + protected GrpcMessagingApplication(GrpcMessingActivity grpcMessingActivity) { this.grpcMessingActivity = grpcMessingActivity; + + ProxyConfig config = ConfigurationManager.getProxyConfig(); + this.routeThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( + config.getGrpcRouteThreadPoolNums(), + config.getGrpcRouteThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "GrpcRouteThreadPool", + config.getGrpcRouteThreadQueueCapacity() + ); + this.producerThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( + config.getGrpcProducerThreadPoolNums(), + config.getGrpcProducerThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "GrpcRouteThreadPool", + config.getGrpcProducerThreadQueueCapacity() + ); + this.consumerThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( + config.getGrpcConsumerThreadPoolNums(), + config.getGrpcConsumerThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "GrpcRouteThreadPool", + config.getGrpcConsumerThreadQueueCapacity() + ); + this.clientManagerThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( + config.getGrpcClientManagerThreadPoolNums(), + config.getGrpcClientManagerThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "GrpcRouteThreadPool", + config.getGrpcClientManagerThreadQueueCapacity() + ); + this.transactionThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( + config.getGrpcTransactionThreadPoolNums(), + config.getGrpcTransactionThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "GrpcRouteThreadPool", + config.getGrpcTransactionThreadQueueCapacity() + ); + + this.init(); } - public static GrpcMessagingApplication create(ServiceManager serviceManager) { + protected void init() { + GrpcTaskRejectedExecutionHandler rejectedExecutionHandler = new GrpcTaskRejectedExecutionHandler(); + this.routeThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + this.routeThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + this.producerThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + this.consumerThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + this.clientManagerThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + this.transactionThreadPoolExecutor.setRejectedExecutionHandler(rejectedExecutionHandler); + } + + public static GrpcMessagingApplication create(MessagingProcessor messagingProcessor) { return new GrpcMessagingApplication(new DefaultGrpcMessingActivity( - serviceManager + messagingProcessor )); } + protected Status flowLimitStatus() { + return ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "flow limit"); + } + protected Status convertExceptionToStatus(Throwable t) { return ResponseBuilder.buildStatus(t); } + protected void addExecutor(ExecutorService executor, Runnable runnable, StreamObserver responseObserver, + T executeRejectResponse) { + executor.submit(new GrpcTask(runnable, responseObserver, executeRejectResponse)); + } + @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.queryRoute(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryRouteResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.routeThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.queryRoute(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + QueryRouteResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + QueryRouteResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.heartbeat(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - HeartbeatResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.clientManagerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.heartbeat(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + HeartbeatResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + HeartbeatResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.sendMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - SendMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.producerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.sendMessage(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + SendMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + SendMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.queryAssignment(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryAssignmentResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.routeThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.queryAssignment(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + QueryAssignmentResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + QueryAssignmentResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - grpcMessingActivity.receiveMessage(Context.current(), request, responseObserver); + Context ctx = Context.current(); + this.addExecutor(this.consumerThreadPoolExecutor, + () -> grpcMessingActivity.receiveMessage(ctx, request, responseObserver), + responseObserver, + ReceiveMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); + } @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.ackMessage(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - AckMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.consumerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.ackMessage(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + AckMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + AckMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); + } @Override public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.forwardMessageToDeadLetterQueue(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.producerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.forwardMessageToDeadLetterQueue(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.endTransaction(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - EndTransactionResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.transactionThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.endTransaction(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + EndTransactionResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + EndTransactionResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.notifyClientTermination(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - NotifyClientTerminationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.clientManagerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.notifyClientTermination(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + NotifyClientTerminationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + NotifyClientTerminationResponse.newBuilder().setStatus(flowLimitStatus()).build()); + } @Override public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { - CompletableFuture future = grpcMessingActivity.changeInvisibleDuration(Context.current(), request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ChangeInvisibleDurationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); + Context ctx = Context.current(); + this.addExecutor(this.consumerThreadPoolExecutor, + () -> { + CompletableFuture future = grpcMessingActivity.changeInvisibleDuration(ctx, request); + future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) + .exceptionally(e -> { + ResponseWriter.write( + responseObserver, + ChangeInvisibleDurationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() + ); + return null; + }); + }, + responseObserver, + ChangeInvisibleDurationResponse.newBuilder().setStatus(flowLimitStatus()).build()); + } @Override public StreamObserver telemetry(StreamObserver responseObserver) { - return grpcMessingActivity.telemetry(Context.current(), responseObserver); + StreamObserver responseTelemetryCommand = grpcMessingActivity.telemetry(Context.current(), responseObserver); + return new StreamObserver() { + @Override + public void onNext(TelemetryCommand value) { + addExecutor(clientManagerThreadPoolExecutor, + () -> responseTelemetryCommand.onNext(value), + responseObserver, + TelemetryCommand.newBuilder().setStatus(flowLimitStatus()).build()); + } + + @Override + public void onError(Throwable t) { + responseTelemetryCommand.onError(t); + } + + @Override + public void onCompleted() { + responseTelemetryCommand.onCompleted(); + } + }; } @Override public void shutdown() throws Exception { this.grpcMessingActivity.shutdown(); + + this.routeThreadPoolExecutor.shutdown(); + this.routeThreadPoolExecutor.shutdown(); + this.producerThreadPoolExecutor.shutdown(); + this.consumerThreadPoolExecutor.shutdown(); + this.clientManagerThreadPoolExecutor.shutdown(); + this.transactionThreadPoolExecutor.shutdown(); } @Override public void start() throws Exception { this.grpcMessingActivity.start(); } + + protected static class GrpcTask implements Runnable { + + private final Runnable runnable; + private final T executeRejectResponse; + private final StreamObserver streamObserver; + + public GrpcTask(Runnable runnable, StreamObserver streamObserver, T executeRejectResponse) { + this.runnable = runnable; + this.streamObserver = streamObserver; + this.executeRejectResponse = executeRejectResponse; + } + + @Override + public void run() { + this.runnable.run(); + } + } + + protected static class GrpcTaskRejectedExecutionHandler implements RejectedExecutionHandler { + + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + if (r instanceof GrpcTask) { + GrpcTask grpcTask = (GrpcTask) r; + ResponseWriter.write(grpcTask.streamObserver, grpcTask.executeRejectResponse); + } + } + } } 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 1824104f6c..b5bb417ba6 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 @@ -19,24 +19,45 @@ package org.apache.rocketmq.proxy.grpc.v2.channel; import io.grpc.Context; import java.util.Map; +import java.util.Set; 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 java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.service.out.ProxyOutResult; import org.apache.rocketmq.proxy.service.out.ProxyOutService; -public class GrpcChannelManager { +public class GrpcChannelManager implements StartAndShutdown { private final ProxyOutService proxyOutService; protected final ConcurrentMap/* clientId */> groupClientIdChannelMap = new ConcurrentHashMap<>(); protected final AtomicLong nonceIdGenerator = new AtomicLong(0); - protected final ConcurrentMap> resultNonceFutureMap = new ConcurrentHashMap<>(); + protected final ConcurrentMap resultNonceFutureMap = new ConcurrentHashMap<>(); + + protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("GrpcChannelManager_") + ); public GrpcChannelManager(ProxyOutService proxyOutService) { this.proxyOutService = proxyOutService; } + protected void init() { + this.scheduledExecutorService.scheduleAtFixedRate( + this::scanExpireResultFuture, + 10, 10, TimeUnit.SECONDS + ); + } + public GrpcClientChannel createChannel(Context ctx, String group, String clientId) { this.groupClientIdChannelMap.compute(group, (groupKey, clientIdMap) -> { if (clientIdMap == null) { @@ -68,17 +89,59 @@ public class GrpcChannelManager { return channelRef.get(); } - public String addResponseFuture(CompletableFuture responseFuture) { + public String addResponseFuture(CompletableFuture> responseFuture) { String nonce = this.nextNonce(); - this.resultNonceFutureMap.put(nonce, responseFuture); + this.resultNonceFutureMap.put(nonce, new ResultFuture<>(responseFuture)); return nonce; } - public CompletableFuture getAndRemoveResponseFuture(String nonce) { - return (CompletableFuture) this.resultNonceFutureMap.remove(nonce); + public CompletableFuture> getAndRemoveResponseFuture(String nonce) { + ResultFuture resultFuture = this.resultNonceFutureMap.remove(nonce); + if (resultFuture != null) { + return resultFuture.future; + } + return null; } protected String nextNonce() { return String.valueOf(this.nonceIdGenerator.getAndIncrement()); } + + protected void scanExpireResultFuture() { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + long timeOutMs = TimeUnit.SECONDS.toMillis(proxyConfig.getGrpcProxyOutRequestTimeoutSecond()); + + Set nonceSet = this.resultNonceFutureMap.keySet(); + for (String nonce : nonceSet) { + ResultFuture resultFuture = this.resultNonceFutureMap.get(nonce); + if (resultFuture == null) { + continue; + } + if (System.currentTimeMillis() - resultFuture.createTime > timeOutMs) { + resultFuture = this.resultNonceFutureMap.remove(nonce); + if (resultFuture != null) { + resultFuture.future.complete(new ProxyOutResult<>(ResponseCode.SYSTEM_BUSY, "call remote timeout", null)); + } + } + } + } + + @Override + public void shutdown() throws Exception { + this.scheduledExecutorService.shutdown(); + } + + @Override + public void start() throws Exception { + + } + + protected static class ResultFuture { + public CompletableFuture> future; + public long createTime = System.currentTimeMillis(); + + public ResultFuture(CompletableFuture> future) { + this.future = future; + } + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 1ad4422a0c..1dbed8eeed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -36,6 +36,7 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.service.out.ProxyChannel; +import org.apache.rocketmq.proxy.service.out.ProxyOutResult; import org.apache.rocketmq.proxy.service.out.ProxyOutService; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.common.RemotingUtil; @@ -153,7 +154,7 @@ public class GrpcClientChannel extends ProxyChannel { @Override protected CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header, - CompletableFuture responseFuture) { + CompletableFuture> responseFuture) { if (!header.isJstackEnable()) { return CompletableFuture.completedFuture(null); } @@ -168,7 +169,7 @@ public class GrpcClientChannel extends ProxyChannel { @Override protected CompletableFuture processConsumeMessageDirectly(RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header, - MessageExt messageExt, CompletableFuture responseFuture) { + MessageExt messageExt, CompletableFuture> responseFuture) { this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() .setVerifyMessageCommand(VerifyMessageCommand.newBuilder() .setNonce(this.grpcChannelManager.addResponseFuture(responseFuture)) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 8e7c9699b7..c0fcdf016e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -25,13 +25,12 @@ import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Status; import apache.rocketmq.v2.SubscriptionEntry; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; import io.grpc.Context; -import io.grpc.Status; -import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; import java.util.HashSet; import java.util.List; @@ -46,6 +45,7 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.body.CMResult; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; @@ -54,17 +54,17 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; -import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; +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.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; -import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.service.out.ProxyOutResult; import org.apache.rocketmq.remoting.protocol.LanguageCode; public class ClientActivity extends AbstractMessingActivity { @@ -142,7 +142,8 @@ public class ClientActivity extends AbstractMessingActivity { return future; } - public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { + public CompletableFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request) { CompletableFuture future = new CompletableFuture<>(); try { @@ -197,18 +198,13 @@ public class ClientActivity extends AbstractMessingActivity { break; } case THREAD_STACK_TRACE: { - reportThreadStackTrace(ctx, request.getThreadStackTrace()); + reportThreadStackTrace(ctx, request.getStatus(), request.getThreadStackTrace()); break; } case VERIFY_MESSAGE_RESULT: { - reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); + reportVerifyMessageResult(ctx, request.getStatus(), request.getVerifyMessageResult()); break; } - default: { - ResponseWriter.writeException(responseObserver, new StatusRuntimeException( - Status.INVALID_ARGUMENT.withDescription("") - )); - } } } @@ -224,7 +220,8 @@ public class ClientActivity extends AbstractMessingActivity { }; } - protected TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { + protected TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, + StreamObserver responseObserver) { ProxyContext context = createContext(ctx); String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); @@ -242,41 +239,49 @@ public class ClientActivity extends AbstractMessingActivity { consumerChannel.setClientObserver(responseObserver); } return TelemetryCommand.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .setSettings(settings) .build(); } - protected void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { + protected void reportThreadStackTrace(Context ctx, Status status, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); - CompletableFuture responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); if (responseFuture != null) { try { - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(threadStack); - responseFuture.complete(runningInfo); + if (status.getCode().equals(Code.OK)) { + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(threadStack); + responseFuture.complete(new ProxyOutResult<>(ResponseCode.SUCCESS, "", runningInfo)); + } else if (status.getCode().equals(Code.VERIFY_MESSAGE_FORBIDDEN)) { + responseFuture.complete(new ProxyOutResult<>(ResponseCode.NO_PERMISSION, "forbidden to verify message", null)); + } else { + responseFuture.complete(new ProxyOutResult<>(ResponseCode.SYSTEM_ERROR, "verify message failed", null)); + } } catch (Throwable t) { responseFuture.completeExceptionally(t); } } } - protected void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { + protected void reportVerifyMessageResult(Context ctx, Status status, VerifyMessageResult request) { String nonce = request.getNonce(); - CompletableFuture responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); if (responseFuture != null) { try { - ConsumeMessageDirectlyResult result = this.buildConsumeMessageDirectlyResult(request); - responseFuture.complete(result); + ConsumeMessageDirectlyResult result = this.buildConsumeMessageDirectlyResult(status, request); + responseFuture.complete(new ProxyOutResult<>(ResponseCode.SUCCESS, "", result)); } catch (Throwable t) { responseFuture.completeExceptionally(t); } } } - protected ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { + protected ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(Status status, + VerifyMessageResult request) { ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); - switch (request.getStatus().getCode().getNumber()) { + switch (status.getCode().getNumber()) { case Code.OK_VALUE: { consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); break; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 810708a216..72db47eccf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -163,7 +163,10 @@ public class GrpcConverter { systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); // born_host - systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); + String bornHostString = messageExt.getBornHostString(); + if (bornHostString != null) { + systemPropertiesBuilder.setBornHost(bornHostString); + } // store_timestamp (millis) long storeTimestamp = messageExt.getStoreTimestamp(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index dd4f2471eb..a36608614a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -50,7 +51,6 @@ import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; public class RouteActivity extends AbstractMessingActivity { public RouteActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { super(messagingProcessor, grpcClientSettingsManager); } @@ -112,26 +112,36 @@ public class RouteActivity extends AbstractMessingActivity { List assignments = new ArrayList<>(); Map> brokerMap = buildBrokerMap(proxyTopicRouteData.getBrokerDatas()); for (QueueData queueData : proxyTopicRouteData.getQueueDatas()) { - Map brokerIdMap = brokerMap.get(queueData.getBrokerName()); - if (brokerIdMap != null) { - for (Map.Entry brokerIdEntry : brokerIdMap.entrySet()) { + if (PermName.isReadable(queueData.getPerm()) && queueData.getReadQueueNums() > 0) { + Map brokerIdMap = brokerMap.get(queueData.getBrokerName()); + if (brokerIdMap != null) { + Broker broker = brokerIdMap.get(MixAll.MASTER_ID); MessageQueue defaultMessageQueue = MessageQueue.newBuilder() .setTopic(request.getTopic()) .setId(-1) .setPermission(this.convertToPermission(queueData.getPerm())) - .setBroker(brokerIdEntry.getValue()) + .setBroker(broker) .build(); assignments.add(Assignment.newBuilder() .setMessageQueue(defaultMessageQueue) .build()); + } } } - QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() - .addAllAssignments(assignments) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); + + QueryAssignmentResponse response; + if (assignments.isEmpty()) { + response = QueryAssignmentResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.FORBIDDEN, "no readable queue")) + .build(); + } else { + response = QueryAssignmentResponse.newBuilder() + .addAllAssignments(assignments) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build(); + } future.complete(response); } catch (Throwable t) { future.completeExceptionally(t); 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 6794615544..63e51f3ea1 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 @@ -20,6 +20,7 @@ package org.apache.rocketmq.proxy.processor; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; @@ -35,6 +36,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; 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.utils.FutureUtils; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; @@ -42,9 +44,12 @@ import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; public class ConsumerProcessor extends AbstractProcessor { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private final ExecutorService executor; + public ConsumerProcessor(MessagingProcessor messagingProcessor, - ServiceManager serviceManager) { + ServiceManager serviceManager, ExecutorService executor) { super(messagingProcessor, serviceManager); + this.executor = executor; } public CompletableFuture popMessage( @@ -86,12 +91,12 @@ public class ConsumerProcessor extends AbstractProcessor { requestHeader.setExp(subscriptionData.getSubString()); requestHeader.setOrder(fifo); - return this.serviceManager.getMessageService().popMessage( + future = this.serviceManager.getMessageService().popMessage( ctx, messageQueue, requestHeader, timeoutMillis) - .thenApply(popResult -> { + .thenApplyAsync(popResult -> { if (PopStatus.FOUND.equals(popResult.getPopStatus()) && popResult.getMsgFoundList() != null && !popResult.getMsgFoundList().isEmpty() && @@ -134,11 +139,11 @@ public class ConsumerProcessor extends AbstractProcessor { popResult.setMsgFoundList(messageExtList); } return popResult; - }); + }, this.executor); } catch (Throwable t) { future.completeExceptionally(t); } - return future; + return FutureUtils.addExecutor(future, this.executor); } public CompletableFuture ackMessage( @@ -160,7 +165,7 @@ public class ConsumerProcessor extends AbstractProcessor { ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); ackMessageRequestHeader.setOffset(handle.getOffset()); - return this.serviceManager.getMessageService().ackMessage( + future = this.serviceManager.getMessageService().ackMessage( ctx, handle, messageId, @@ -169,7 +174,7 @@ public class ConsumerProcessor extends AbstractProcessor { } catch (Throwable t) { future.completeExceptionally(t); } - return future; + return FutureUtils.addExecutor(future, this.executor); } public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, @@ -186,7 +191,7 @@ public class ConsumerProcessor extends AbstractProcessor { changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); changeInvisibleTimeRequestHeader.setInvisibleTime(invisibleTime); - return this.serviceManager.getMessageService().changeInvisibleTime( + future = this.serviceManager.getMessageService().changeInvisibleTime( ctx, handle, messageId, @@ -195,6 +200,6 @@ public class ConsumerProcessor extends AbstractProcessor { } catch (Throwable t) { future.completeExceptionally(t); } - return future; + return FutureUtils.addExecutor(future, this.executor); } } 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 e89330ed76..a590da8ed6 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 @@ -20,6 +20,9 @@ import io.netty.channel.Channel; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; @@ -33,16 +36,22 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.utils.FutureUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.out.ProxyOutService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class DefaultMessagingProcessor implements MessagingProcessor { +public class DefaultMessagingProcessor extends AbstractStartAndShutdown implements MessagingProcessor { private final ServiceManager serviceManager; private final ProducerProcessor producerProcessor; @@ -50,12 +59,57 @@ public class DefaultMessagingProcessor implements MessagingProcessor { private final TransactionProcessor transactionProcessor; private final ClientProcessor clientProcessor; - public DefaultMessagingProcessor(ServiceManager serviceManager) { + protected final ThreadPoolExecutor producerProcessorExecutor; + protected final ThreadPoolExecutor consumerProcessorExecutor; + + protected DefaultMessagingProcessor(ServiceManager serviceManager) { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + this.producerProcessorExecutor = ThreadPoolMonitor.createAndMonitor( + proxyConfig.getProducerProcessorThreadPoolNums(), + proxyConfig.getProducerProcessorThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "ProducerProcessorExecutor", + proxyConfig.getProducerProcessorThreadPoolQueueCapacity() + ); + this.consumerProcessorExecutor = ThreadPoolMonitor.createAndMonitor( + proxyConfig.getConsumerProcessorThreadPoolNums(), + proxyConfig.getConsumerProcessorThreadPoolNums(), + 1, + TimeUnit.MINUTES, + "ConsumerProcessorExecutor", + proxyConfig.getConsumerProcessorThreadPoolQueueCapacity() + ); + this.serviceManager = serviceManager; - this.producerProcessor = new ProducerProcessor(this, serviceManager); - this.consumerProcessor = new ConsumerProcessor(this, serviceManager); + this.producerProcessor = new ProducerProcessor(this, serviceManager, this.producerProcessorExecutor); + this.consumerProcessor = new ConsumerProcessor(this, serviceManager, this.consumerProcessorExecutor); this.transactionProcessor = new TransactionProcessor(this, serviceManager); this.clientProcessor = new ClientProcessor(this, serviceManager); + + this.init(); + } + + public static DefaultMessagingProcessor createForLocalMode(BrokerController brokerController) { + return createForLocalMode(brokerController, null); + } + + public static DefaultMessagingProcessor createForLocalMode(BrokerController brokerController, RPCHook rpcHook) { + return new DefaultMessagingProcessor(ServiceManager.createForLocalMode(brokerController, rpcHook)); + } + + public static DefaultMessagingProcessor createForClusterMode() { + return createForClusterMode(null); + } + + public static DefaultMessagingProcessor createForClusterMode(RPCHook rpcHook) { + return new DefaultMessagingProcessor(ServiceManager.createForClusterMode(rpcHook)); + } + + protected void init() { + this.appendStartAndShutdown(this.serviceManager); + this.appendShutdown(this.producerProcessorExecutor::shutdown); + this.appendShutdown(this.consumerProcessorExecutor::shutdown); } @Override @@ -78,7 +132,8 @@ public class DefaultMessagingProcessor implements MessagingProcessor { @Override public void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId, - String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, + long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { this.transactionProcessor.endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, 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 9fdb8afc4b..3f29fe2f6c 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 @@ -36,13 +36,14 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.out.ProxyOutService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public interface MessagingProcessor { +public interface MessagingProcessor extends StartAndShutdown { long DEFAULT_TIMEOUT_MILLS = Duration.ofSeconds(2).toMillis(); 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 dfd6395e59..086151e96b 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 @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.processor; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.consumer.ReceiptHandle; @@ -31,15 +32,19 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; 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.utils.FutureUtils; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerProcessor extends AbstractProcessor { + private final ExecutorService executor; + public ProducerProcessor(MessagingProcessor messagingProcessor, - ServiceManager serviceManager) { + ServiceManager serviceManager, ExecutorService executor) { super(messagingProcessor, serviceManager); + this.executor = executor; } public CompletableFuture sendMessage(ProxyContext ctx, QueueSelector queueSelector, @@ -55,7 +60,7 @@ public class ProducerProcessor extends AbstractProcessor { SendMessageRequestHeader requestHeader = buildSendMessageRequestHeader(messageExtList, producerGroup, messageQueue.getQueueId()); - return this.serviceManager.getMessageService().sendMessage( + future = this.serviceManager.getMessageService().sendMessage( ctx, messageQueue, messageExtList, @@ -64,7 +69,7 @@ public class ProducerProcessor extends AbstractProcessor { } catch (Throwable t) { future.completeExceptionally(t); } - return future; + return FutureUtils.addExecutor(future, this.executor); } protected SendMessageRequestHeader buildSendMessageRequestHeader(List messageExtList, @@ -107,6 +112,10 @@ public class ProducerProcessor extends AbstractProcessor { String messageId, String groupName, String topicName, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); try { + if (handle.getCommitLogOffset() < 0) { + throw new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "commit log offset is empty"); + } + ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); consumerSendMsgBackRequestHeader.setGroup(groupName); @@ -115,22 +124,22 @@ public class ProducerProcessor extends AbstractProcessor { consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(0); - return this.serviceManager.getMessageService().sendMessageBack( + future = this.serviceManager.getMessageService().sendMessageBack( ctx, handle, messageId, consumerSendMsgBackRequestHeader, timeoutMillis - ).whenComplete((remotingCommand, t) -> { + ).whenCompleteAsync((remotingCommand, t) -> { if (t == null && remotingCommand.getCode() == ResponseCode.SUCCESS) { this.messagingProcessor.ackMessage(ctx, handle, messageId, groupName, topicName, timeoutMillis); } - }); + }, this.executor); } catch (Throwable t) { future.completeExceptionally(t); } - return future; + return FutureUtils.addExecutor(future, this.executor); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java index d548271f9d..138c38761b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java @@ -31,8 +31,9 @@ public class TransactionProcessor extends AbstractProcessor { super(messagingProcessor, serviceManager); } - void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId,String producerGroup, - TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId, String producerGroup, + TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) + throws MQBrokerException, RemotingException, InterruptedException { EndTransactionRequestHeader requestHeader = buildEndTransactionRequestHeader(transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck); @@ -44,11 +45,8 @@ public class TransactionProcessor extends AbstractProcessor { ); } - protected EndTransactionRequestHeader buildEndTransactionRequestHeader(TransactionId transactionId, String messageId,String producerGroup, - TransactionStatus transactionStatus, boolean fromTransactionCheck) { - long transactionStateTableOffset = transactionId.getTranStateTableOffset(); - long commitLogOffset = transactionId.getCommitLogOffset(); - + protected EndTransactionRequestHeader buildEndTransactionRequestHeader(TransactionId transactionId, + String messageId, String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck) { int commitOrRollback; switch (transactionStatus) { case COMMIT: @@ -66,8 +64,8 @@ public class TransactionProcessor extends AbstractProcessor { endTransactionRequestHeader.setProducerGroup(producerGroup); endTransactionRequestHeader.setMsgId(messageId); endTransactionRequestHeader.setTransactionId(transactionId.getBrokerTransactionId()); - endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); - endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); + endTransactionRequestHeader.setTranStateTableOffset(transactionId.getTranStateTableOffset()); + endTransactionRequestHeader.setCommitLogOffset(transactionId.getCommitLogOffset()); endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); 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 4a548883f2..935f25a8ae 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 @@ -62,12 +62,9 @@ public class ClusterServiceManager extends ServiceManager { this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - double workerFactor = proxyConfig.getRocketmqMQClientWorkerFactor(); - int threadCount = (int) Math.ceil(Runtime.getRuntime().availableProcessors() * workerFactor); this.mqClientAPIFactory = new MQClientAPIFactory( "CLUSTER_MQ_CLIENT_", proxyConfig.getRocketmqMQClientNum(), - threadCount, new DoNothingClientRemotingProcessor(null), rpcHook, scheduledExecutorService); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java index b9e17d228b..abdfa5404a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java @@ -35,17 +35,15 @@ public class MQClientAPIFactory implements StartAndShutdown { private MQClientAPIExt[] clients; private final String namePrefix; private final int clientNum; - private final int bootstrapWorkerThreads; private final ClientRemotingProcessor clientRemotingProcessor; private final RPCHook rpcHook; private final ScheduledExecutorService scheduledExecutorService; - public MQClientAPIFactory(String namePrefix, int clientNum, int bootstrapWorkerThreads, + public MQClientAPIFactory(String namePrefix, int clientNum, ClientRemotingProcessor clientRemotingProcessor, RPCHook rpcHook, ScheduledExecutorService scheduledExecutorService) { this.namePrefix = namePrefix; this.clientNum = clientNum; - this.bootstrapWorkerThreads = bootstrapWorkerThreads; this.clientRemotingProcessor = clientRemotingProcessor; this.rpcHook = rpcHook; this.scheduledExecutorService = scheduledExecutorService; @@ -93,8 +91,6 @@ public class MQClientAPIFactory implements StartAndShutdown { clientConfig.setInstanceName(instanceName); NettyClientConfig nettyClientConfig = new NettyClientConfig(); - nettyClientConfig.setBootstrapWorkerThreads(bootstrapWorkerThreads); - nettyClientConfig.setDisableNettyWorkerGroup(true); nettyClientConfig.setDisableCallbackExecutor(true); MQClientAPIExt mqClientAPIExt = new MQClientAPIExt(clientConfig, nettyClientConfig, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java index 4e4e6e36c6..e6f8abc192 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java @@ -29,14 +29,13 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ClusterProxyOutService implements ProxyOutService { @Override - public CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { - return new CompletableFuture<>(); + return null; } - @Override - public CompletableFuture processConsumeMessageDirectly(RemotingCommand command, - ConsumeMessageDirectlyResultRequestHeader header) { - return new CompletableFuture<>(); + @Override public CompletableFuture> processConsumeMessageDirectly( + RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { + return null; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java index 1b3d5baed8..0a243600f5 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java @@ -36,27 +36,30 @@ public class LocalProxyOutService implements ProxyOutService { } @Override - public CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { - CompletableFuture future = new CompletableFuture<>(); - future.thenAccept(consumerRunningInfo -> { - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "from gRPC client"); - remotingCommand.setOpaque(command.getOpaque()); - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(consumerRunningInfo.getJstack()); - remotingCommand.setBody(runningInfo.encode()); + CompletableFuture> future = new CompletableFuture<>(); + future.thenAccept(proxyOutResult -> { + if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { + ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "from gRPC client"); + remotingCommand.setOpaque(command.getOpaque()); + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack(consumerRunningInfo.getJstack()); + remotingCommand.setBody(runningInfo.encode()); - // nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); + // nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); + } } }); return future; } @Override - public CompletableFuture processConsumeMessageDirectly(RemotingCommand command, + public CompletableFuture> processConsumeMessageDirectly(RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java index a085013096..1a85a96d65 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java @@ -116,13 +116,13 @@ public abstract class ProxyChannel extends AbstractChannel { protected abstract CompletableFuture processGetConsumerRunningInfo( RemotingCommand command, GetConsumerRunningInfoRequestHeader header, - CompletableFuture responseFuture); + CompletableFuture> responseFuture); protected abstract CompletableFuture processConsumeMessageDirectly( RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header, MessageExt messageExt, - CompletableFuture responseFuture); + CompletableFuture> responseFuture); @Override public ChannelConfig config() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java new file mode 100644 index 0000000000..efeccbafd1 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.out; + +public class ProxyOutResult { + private int code; + private String remark; + private T result; + + public ProxyOutResult(int code, String remark, T result) { + this.code = code; + this.remark = remark; + this.result = result; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java index 923c410681..dbe0f13255 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java @@ -25,12 +25,12 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface ProxyOutService { - CompletableFuture processGetConsumerRunningInfo( + CompletableFuture> processGetConsumerRunningInfo( RemotingCommand command, GetConsumerRunningInfoRequestHeader header ); - CompletableFuture processConsumeMessageDirectly( + CompletableFuture> processConsumeMessageDirectly( RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header ); 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 f1d3df58e0..aa7e5ec359 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 @@ -57,24 +57,23 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown { new ThreadFactoryImpl("TopicRouteService_") ); this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( - config.getTopicRouteThreadPoolNums(), - config.getTopicRouteThreadPoolNums(), + config.getTopicRouteServiceThreadPoolNums(), + config.getTopicRouteServiceThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, "TopicRouteCacheRefresh", - config.getTopicRouteThreadPoolQueueCapacity() + config.getTopicRouteServiceThreadPoolQueueCapacity() ); this.mqClientAPIFactory = new MQClientAPIFactory( "TopicRouteServiceClient_", 1, - 1, new DoNothingClientRemotingProcessor(null), rpcHook, this.scheduledExecutorService ); this.topicCache = CacheBuilder.newBuilder() - .maximumSize(config.getTopicRouteCacheMaxNum()) - .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) + .maximumSize(config.getTopicRouteServiceCacheMaxNum()) + .refreshAfterWrite(config.getTopicRouteServiceCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new TopicRouteCacheLoader()); this.init(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index be5e3b0171..c892d3ef74 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -69,7 +69,6 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS this.mqClientAPIFactory = new MQClientAPIFactory( "ClusterTransaction_", 1, - 1, new ProxyClientRemotingProcessor(producerManager), rpcHook, scheduledExecutorService); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java new file mode 100644 index 0000000000..2217ce4e7a --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -0,0 +1,82 @@ +/* + * 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.grpc.v2; + +import io.grpc.Context; +import io.grpc.Metadata; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.when; + +@Ignore +@RunWith(MockitoJUnitRunner.Silent.class) +public class BaseActivityTest extends InitConfigAndLoggerTest { + protected static final Random RANDOM = new Random(); + @Mock + protected MessagingProcessor messagingProcessor; + @Mock + protected GrpcClientSettingsManager grpcClientSettingsManager; + @Mock + protected ProxyOutService proxyOutService; + + protected static final String REMOTE_ADDR = "192.168.0.1:8080"; + protected static final String LOCAL_ADDR = "127.0.0.1:8080"; + protected Metadata metadata = new Metadata(); + + public void before() throws Throwable { + super.before(); + metadata.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); + metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); + when(messagingProcessor.getProxyOutService()).thenReturn(proxyOutService); + } + + protected Context createContext() { + Context context = Context.current(); + return context.withValue(InterceptorConstants.METADATA, metadata) + .withDeadlineAfter(10, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); + } + + protected static String buildReceiptHandle(String topic, long popTime, long invisibleTime) { + return ExtraInfoUtil.buildExtraInfo( + RANDOM.nextInt(Integer.MAX_VALUE), + popTime, + invisibleTime, + 0, + topic, + "brokerName", + RANDOM.nextInt(8), + RANDOM.nextInt(Integer.MAX_VALUE) + ); + } +} 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 new file mode 100644 index 0000000000..353b145fba --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/AckMessageActivityTest.java @@ -0,0 +1,91 @@ +/* + * 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.grpc.v2.consumer; + +import apache.rocketmq.v2.AckMessageEntry; +import apache.rocketmq.v2.AckMessageRequest; +import apache.rocketmq.v2.AckMessageResponse; +import apache.rocketmq.v2.Code; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.proxy.common.ProxyException; +import org.apache.rocketmq.proxy.common.ProxyExceptionCode; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class AckMessageActivityTest extends BaseActivityTest { + + private AckMessageActivity ackMessageActivity; + + private static final String TOPIC = "topic"; + + @Before + public void before() throws Throwable { + super.before(); + this.ackMessageActivity = new AckMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testAckMessage() throws Throwable { + when(this.messagingProcessor.ackMessage(any(), any(), eq("msg1"), anyString(), anyString())) + .thenThrow(new ProxyException(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, "receipt handle is expired")); + + AckResult msg2AckResult = new AckResult(); + msg2AckResult.setStatus(AckStatus.OK); + 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())) + .thenReturn(CompletableFuture.completedFuture(msg3AckResult)); + + AckMessageResponse response = this.ackMessageActivity.ackMessage( + createContext(), + AckMessageRequest.newBuilder() + .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.OK, response.getStatus().getCode()); + assertEquals(3, response.getEntriesCount()); + assertEquals(Code.RECEIPT_HANDLE_EXPIRED, response.getEntries(0).getStatus().getCode()); + assertEquals(Code.OK, response.getEntries(1).getStatus().getCode()); + assertEquals(Code.INTERNAL_SERVER_ERROR, response.getEntries(2).getStatus().getCode()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java new file mode 100644 index 0000000000..cf1c8b7983 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.consumer; + +import apache.rocketmq.v2.ChangeInvisibleDurationRequest; +import apache.rocketmq.v2.ChangeInvisibleDurationResponse; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Resource; +import com.google.protobuf.util.Durations; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +public class ChangeInvisibleDurationActivityTest extends BaseActivityTest { + + private static final String TOPIC = "topic"; + private static final String CONSUMER_GROUP = "consumerGroup"; + private ChangeInvisibleDurationActivity changeInvisibleDurationActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testChangeInvisibleDurationActivity() throws Throwable { + String newHandle = "newHandle"; + ArgumentCaptor invisibleTimeArgumentCaptor = ArgumentCaptor.forClass(Long.class); + AckResult ackResult = new AckResult(); + ackResult.setExtraInfo(newHandle); + ackResult.setStatus(AckStatus.OK); + when(this.messagingProcessor.changeInvisibleTime( + any(), any(), anyString(), anyString(), anyString(), invisibleTimeArgumentCaptor.capture() + )).thenReturn(CompletableFuture.completedFuture(ackResult)); + + ChangeInvisibleDurationResponse response = this.changeInvisibleDurationActivity.changeInvisibleDuration( + createContext(), + ChangeInvisibleDurationRequest.newBuilder() + .setInvisibleDuration(Durations.fromSeconds(3)) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageId("msgId") + .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000)) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(TimeUnit.SECONDS.toMillis(3), invisibleTimeArgumentCaptor.getValue().longValue()); + assertEquals(newHandle, response.getReceiptHandle()); + } + + @Test + public void testChangeInvisibleDurationActivityFailed() throws Throwable { + ArgumentCaptor invisibleTimeArgumentCaptor = ArgumentCaptor.forClass(Long.class); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.NO_EXIST); + when(this.messagingProcessor.changeInvisibleTime( + any(), any(), anyString(), anyString(), anyString(), invisibleTimeArgumentCaptor.capture() + )).thenReturn(CompletableFuture.completedFuture(ackResult)); + + ChangeInvisibleDurationResponse response = this.changeInvisibleDurationActivity.changeInvisibleDuration( + createContext(), + ChangeInvisibleDurationRequest.newBuilder() + .setInvisibleDuration(Durations.fromSeconds(3)) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageId("msgId") + .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000)) + .build() + ).get(); + + assertEquals(Code.INTERNAL_SERVER_ERROR, response.getStatus().getCode()); + assertEquals(TimeUnit.SECONDS.toMillis(3), invisibleTimeArgumentCaptor.getValue().longValue()); + } +} \ 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 new file mode 100644 index 0000000000..86cb54dd59 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivityTest.java @@ -0,0 +1,118 @@ +/* + * 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.grpc.v2.consumer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; +import io.grpc.stub.ServerCallStreamObserver; +import io.grpc.stub.StreamObserver; +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ReceiveMessageActivityTest extends BaseActivityTest { + + private static final String TOPIC = "topic"; + private static final String CONSUMER_GROUP = "consumerGroup"; + private ReceiveMessageActivity receiveMessageActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.receiveMessageActivity = new ReceiveMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testReceiveMessageIllegalFilter() { + StreamObserver receiveStreamObserver = mock(ServerCallStreamObserver.class); + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + + this.receiveMessageActivity.receiveMessage( + createContext(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.SQL) + .setExpression("") + .build()) + .build(), + receiveStreamObserver + ); + + assertEquals(Code.ILLEGAL_FILTER_EXPRESSION, responseArgumentCaptor.getValue().getStatus().getCode()); + } + + @Test + public void testReceiveMessage() { + StreamObserver receiveStreamObserver = mock(ServerCallStreamObserver.class); + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + + PopResult popResult = new PopResult(PopStatus.NO_NEW_MSG, new ArrayList<>()); + when(this.messagingProcessor.popMessage( + any(), + any(), + anyString(), + anyString(), + anyInt(), + anyLong(), + anyLong(), + anyInt(), + any(), + anyBoolean(), + any(), + anyLong() + )).thenReturn(CompletableFuture.completedFuture(popResult)); + + this.receiveMessageActivity.receiveMessage( + createContext(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.TAG) + .setExpression("*") + .build()) + .build(), + receiveStreamObserver + ); + assertEquals(Code.MESSAGE_NOT_FOUND, responseArgumentCaptor.getValue().getStatus().getCode()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java new file mode 100644 index 0000000000..1855220a5e --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.consumer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.ReceiveMessageRequest; +import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Resource; +import io.grpc.stub.StreamObserver; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class ReceiveMessageResponseStreamWriterTest extends BaseActivityTest { + + private static final String TOPIC = "topic"; + private static final String CONSUMER_GROUP = "consumerGroup"; + private ReceiveMessageResponseStreamWriter writer; + private StreamObserver streamObserver; + + @Before + public void before() throws Throwable { + super.before(); + this.streamObserver = mock(StreamObserver.class); + this.writer = new ReceiveMessageResponseStreamWriter(this.messagingProcessor, this.streamObserver); + } + + @Test + public void testWriteMessage() { + ArgumentCaptor changeInvisibleTimeMsgIdCaptor = ArgumentCaptor.forClass(String.class); + doReturn(CompletableFuture.completedFuture(mock(AckResult.class))).when(this.messagingProcessor) + .changeInvisibleTime(any(), any(), changeInvisibleTimeMsgIdCaptor.capture(), anyString(), anyString(), anyLong()); + + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + AtomicInteger onNextCallNum = new AtomicInteger(0); + doAnswer(mock -> { + if (onNextCallNum.incrementAndGet() > 2) { + throw new RuntimeException(); + } + return null; + }).when(streamObserver).onNext(responseArgumentCaptor.capture()); + + List messageExtList = new ArrayList<>(); + messageExtList.add(createMessageExt(TOPIC, "tag")); + messageExtList.add(createMessageExt(TOPIC, "tag")); + PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); + writer.write( + ProxyContext.create(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.TAG) + .setExpression("*") + .build()) + .build(), + popResult + ); + + verify(streamObserver, times(1)).onCompleted(); + verify(streamObserver, times(3)).onNext(any()); + verify(this.messagingProcessor, times(1)) + .changeInvisibleTime(any(), any(), anyString(), anyString(), anyString(), anyLong()); + + assertTrue(responseArgumentCaptor.getAllValues().get(0).hasStatus()); + assertEquals(Code.OK, responseArgumentCaptor.getAllValues().get(0).getStatus().getCode()); + assertTrue(responseArgumentCaptor.getAllValues().get(1).hasMessage()); + assertEquals(messageExtList.get(0).getMsgId(), responseArgumentCaptor.getAllValues().get(1).getMessage().getSystemProperties().getMessageId()); + + assertEquals(messageExtList.get(1).getMsgId(), changeInvisibleTimeMsgIdCaptor.getValue()); + } + + @Test + public void testPollingFull() { + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + doNothing().when(streamObserver).onNext(responseArgumentCaptor.capture()); + + PopResult popResult = new PopResult(PopStatus.POLLING_FULL, new ArrayList<>()); + writer.write( + ProxyContext.create(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setFilterExpression(FilterExpression.newBuilder() + .setType(FilterType.TAG) + .setExpression("*") + .build()) + .build(), + popResult + ); + + assertEquals(Code.TOO_MANY_REQUESTS, responseArgumentCaptor.getValue().getStatus().getCode()); + } + + private static MessageExt createMessageExt(String topic, String tags) { + String msgId = MessageClientIDSetter.createUniqID(); + + MessageExt messageExt = new MessageExt(); + messageExt.setTopic(topic); + messageExt.setTags(tags); + messageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + messageExt.setMsgId(msgId); + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, msgId); + messageExt.setCommitLogOffset(RANDOM.nextInt(Integer.MAX_VALUE)); + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_POP_CK, + ExtraInfoUtil.buildExtraInfo(RANDOM.nextInt(Integer.MAX_VALUE), System.currentTimeMillis(), 3000, + RANDOM.nextInt(Integer.MAX_VALUE), topic, "mockBroker", RANDOM.nextInt(Integer.MAX_VALUE), RANDOM.nextInt(Integer.MAX_VALUE))); + return messageExt; + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java new file mode 100644 index 0000000000..ebb821fd3b --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -0,0 +1,235 @@ +/* + * 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.grpc.v2.route; + +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Broker; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.Permission; +import apache.rocketmq.v2.QueryAssignmentRequest; +import apache.rocketmq.v2.QueryAssignmentResponse; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; +import com.google.common.net.HostAndPort; +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +public class RouteActivityTest extends BaseActivityTest { + + private RouteActivity routeActivity; + + private static final String CLUSTER = "cluster"; + private static final String TOPIC = "topic"; + private static final String BROKER_NAME = "brokerName"; + private static final Broker GRPC_BROKER = Broker.newBuilder().setName(BROKER_NAME).build(); + private static final Resource GRPC_TOPIC = Resource.newBuilder() + .setName(TOPIC) + .build(); + private static Endpoints GRPC_ENDPOINTS = Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder().setHost("127.0.0.1").setPort(8080).build()) + .addAddresses(Address.newBuilder().setHost("127.0.0.2").setPort(8080).build()) + .build(); + private static List ENDPOINTS_ADDRESS = new ArrayList<>(); + + static { + ENDPOINTS_ADDRESS.add(new org.apache.rocketmq.proxy.common.Address( + org.apache.rocketmq.proxy.common.Address.AddressScheme.IPv4, + HostAndPort.fromParts("127.0.0.1", 8080))); + ENDPOINTS_ADDRESS.add(new org.apache.rocketmq.proxy.common.Address( + org.apache.rocketmq.proxy.common.Address.AddressScheme.IPv4, + HostAndPort.fromParts("127.0.0.2", 8080))); + } + + @Before + public void before() throws Throwable { + super.before(); + this.routeActivity = new RouteActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testQueryRoute() throws Throwable { + ArgumentCaptor> addressListCaptor = ArgumentCaptor.forClass(List.class); + when(this.messagingProcessor.getTopicRouteDataForProxy(any(), addressListCaptor.capture(), anyString())) + .thenReturn(createProxyTopicRouteData(2, 2, 6)); + + QueryRouteResponse response = this.routeActivity.queryRoute( + createContext(), + QueryRouteRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .build() + ).get(); + + assertEquals(ENDPOINTS_ADDRESS, addressListCaptor.getValue()); + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(4, response.getMessageQueuesCount()); + for (MessageQueue messageQueue : response.getMessageQueuesList()) { + assertEquals(GRPC_ENDPOINTS, messageQueue.getBroker().getEndpoints()); + assertEquals(Permission.READ_WRITE, messageQueue.getPermission()); + } + } + + @Test + public void testQueryRouteTopicExist() throws Throwable { + when(this.messagingProcessor.getTopicRouteDataForProxy(any(), any(), anyString())) + .thenThrow(new MQBrokerException(ResponseCode.TOPIC_NOT_EXIST, "")); + + QueryRouteResponse response = this.routeActivity.queryRoute( + createContext(), + QueryRouteRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(GRPC_TOPIC) + .build() + ).get(); + + assertEquals(Code.TOPIC_NOT_FOUND, response.getStatus().getCode()); + } + + @Test + public void testQueryAssignmentWithNoReadPerm() throws Throwable { + when(this.messagingProcessor.getTopicRouteDataForProxy(any(), any(), anyString())) + .thenReturn(createProxyTopicRouteData(2, 2, PermName.PERM_WRITE)); + + QueryAssignmentResponse response = this.routeActivity.queryAssignment( + createContext(), + QueryAssignmentRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(GRPC_TOPIC) + .build() + ).get(); + + assertEquals(Code.FORBIDDEN, response.getStatus().getCode()); + } + + @Test + public void testQueryAssignmentWithNoReadQueue() throws Throwable { + when(this.messagingProcessor.getTopicRouteDataForProxy(any(), any(), anyString())) + .thenReturn(createProxyTopicRouteData(0, 2, 6)); + + QueryAssignmentResponse response = this.routeActivity.queryAssignment( + createContext(), + QueryAssignmentRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(GRPC_TOPIC) + .build() + ).get(); + + assertEquals(Code.FORBIDDEN, response.getStatus().getCode()); + } + + @Test + public void testQueryAssignment() throws Throwable { + when(this.messagingProcessor.getTopicRouteDataForProxy(any(), any(), anyString())) + .thenReturn(createProxyTopicRouteData(2, 2, 6)); + + QueryAssignmentResponse response = this.routeActivity.queryAssignment( + createContext(), + QueryAssignmentRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(GRPC_TOPIC) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(1, response.getAssignmentsCount()); + assertEquals(GRPC_ENDPOINTS, response.getAssignments(0).getMessageQueue().getBroker().getEndpoints()); + } + + private static ProxyTopicRouteData createProxyTopicRouteData(int r, int w, int p) { + ProxyTopicRouteData proxyTopicRouteData = new ProxyTopicRouteData(); + proxyTopicRouteData.getQueueDatas().add(createQueueData(r, w, p)); + ProxyTopicRouteData.ProxyBrokerData proxyBrokerData = new ProxyTopicRouteData.ProxyBrokerData(); + proxyBrokerData.setCluster(CLUSTER); + proxyBrokerData.setBrokerName(BROKER_NAME); + proxyBrokerData.getBrokerAddrs().put(0L, ENDPOINTS_ADDRESS); + proxyBrokerData.getBrokerAddrs().put(1L, ENDPOINTS_ADDRESS); + proxyTopicRouteData.getBrokerDatas().add(proxyBrokerData); + return proxyTopicRouteData; + } + + @Test + public void testGenPartitionFromQueueData() throws Exception { + // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. + QueueData queueDataWith8R8WPermRW = createQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith8R8WPermRW = this.routeActivity.genMessageQueueFromQueueData(queueDataWith8R8WPermRW, GRPC_TOPIC, GRPC_BROKER); + assertEquals(8, partitionWith8R8WPermRW.size()); + assertEquals(8, partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()); + assertEquals(0, partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()); + assertEquals(0, partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()); + + // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. + QueueData queueDataWith8R8WPermR = createQueueData(8, 8, PermName.PERM_READ); + List partitionWith8R8WPermR = this.routeActivity.genMessageQueueFromQueueData(queueDataWith8R8WPermR, GRPC_TOPIC, GRPC_BROKER); + assertEquals(8, partitionWith8R8WPermR.size()); + assertEquals(8, partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()); + assertEquals(0, partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()); + assertEquals(0, partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.WRITE).count()); + + // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. + QueueData queueDataWith8R8WPermW = createQueueData(8, 8, PermName.PERM_WRITE); + List partitionWith8R8WPermW = this.routeActivity.genMessageQueueFromQueueData(queueDataWith8R8WPermW, GRPC_TOPIC, GRPC_BROKER); + assertEquals(8, partitionWith8R8WPermW.size()); + assertEquals(8, partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()); + assertEquals(0, partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()); + assertEquals(0, partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ).count()); + + // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. + QueueData queueDataWith8R0WPermRW = createQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith8R0WPermRW = this.routeActivity.genMessageQueueFromQueueData(queueDataWith8R0WPermRW, GRPC_TOPIC, GRPC_BROKER); + assertEquals(8, partitionWith8R0WPermRW.size()); + assertEquals(8, partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()); + assertEquals(0, partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()); + assertEquals(0, partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()); + + // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. + QueueData queueDataWith4R8WPermRW = createQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); + List partitionWith4R8WPermRW = this.routeActivity.genMessageQueueFromQueueData(queueDataWith4R8WPermRW, GRPC_TOPIC, GRPC_BROKER); + assertEquals(8, partitionWith4R8WPermRW.size()); + assertEquals(4, partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()); + assertEquals(4, partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()); + assertEquals(0, partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()); + } + + private static QueueData createQueueData(int r, int w, int perm) { + QueueData queueData = new QueueData(); + queueData.setBrokerName(BROKER_NAME); + queueData.setReadQueueNums(r); + queueData.setWriteQueueNums(w); + queueData.setPerm(perm); + return queueData; + } +} \ No newline at end of file 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 152b66c82a..5e0a256e12 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 @@ -17,13 +17,11 @@ package org.apache.rocketmq.proxy.processor; -import io.netty.util.internal.MathUtil; import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.UUID; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; -import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; @@ -94,10 +92,10 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { messageExt.setReconsumeTimes(reconsumeTimes); messageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); messageExt.setMsgId(MessageClientIDSetter.createUniqID()); - messageExt.setCommitLogOffset(RANDOM.nextInt()); + messageExt.setCommitLogOffset(RANDOM.nextInt(Integer.MAX_VALUE)); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_POP_CK, - ExtraInfoUtil.buildExtraInfo(RANDOM.nextInt(), System.currentTimeMillis(), invisibleTime, - RANDOM.nextInt(), topic, "mockBroker", RANDOM.nextInt(), RANDOM.nextInt())); + 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))); 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 f2547a8b78..dbac6b4e99 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 @@ -21,6 +21,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; @@ -63,7 +64,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { @Before public void before() throws Throwable { super.before(); - this.consumerProcessor = new ConsumerProcessor(this.messagingProcessor, this.serviceManager); + this.consumerProcessor = new ConsumerProcessor(this.messagingProcessor, this.serviceManager, Executors.newCachedThreadPool()); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 6d4e45c6ce..9f138fd562 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -17,8 +17,98 @@ package org.apache.rocketmq.proxy.processor; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.KeyBuilder; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ProducerProcessorTest extends BaseProcessorTest { + private static final String PRODUCER_GROUP = "producerGroup"; + private static final String CONSUMER_GROUP = "consumerGroup"; + private static final String TOPIC = "topic"; + + private ProducerProcessor producerProcessor; + + @Before + public void before() throws Throwable { + super.before(); + this.producerProcessor = new ProducerProcessor(this.messagingProcessor, this.serviceManager, Executors.newCachedThreadPool()); + } + + @Test + public void testSendMessage() throws Throwable { + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); + when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(mock(SendResult.class))); + + List messageExtList = new ArrayList<>(); + MessageExt messageExt = createMessageExt(MixAll.getRetryTopic(CONSUMER_GROUP), "tag", 0, 0); + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_RECONSUME_TIME, "1"); + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_MAX_RECONSUME_TIMES, "16"); + messageExtList.add(messageExt); + SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + + SendResult sendResult = this.producerProcessor.sendMessage( + createContext(), + (ctx, messageQueueView) -> messageQueue, + PRODUCER_GROUP, + messageExtList, + 3000 + ).get(); + + assertNotNull(sendResult); + SendMessageRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); + assertEquals(PRODUCER_GROUP, requestHeader.getProducerGroup()); + assertEquals(MixAll.getRetryTopic(CONSUMER_GROUP), requestHeader.getTopic()); + assertEquals(1, requestHeader.getReconsumeTimes().intValue()); + assertEquals(16, requestHeader.getMaxReconsumeTimes().intValue()); + } + + @Test + public void testForwardMessageToDeadLetterQueue() throws Throwable { + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); + when(this.messageService.sendMessageBack(any(), any(), anyString(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(mock(RemotingCommand.class))); + + MessageExt messageExt = createMessageExt(KeyBuilder.buildPopRetryTopic(TOPIC, CONSUMER_GROUP), "", 16, 3000); + RemotingCommand remotingCommand = this.producerProcessor.forwardMessageToDeadLetterQueue( + createContext(), + ReceiptHandle.create(messageExt), + messageExt.getMsgId(), + CONSUMER_GROUP, + TOPIC, + 3000 + ).get(); + + assertNotNull(remotingCommand); + ConsumerSendMsgBackRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); + assertEquals(messageExt.getTopic(), requestHeader.getOriginTopic()); + assertEquals(messageExt.getMsgId(), requestHeader.getOriginMsgId()); + assertEquals(CONSUMER_GROUP, requestHeader.getGroup()); + } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java new file mode 100644 index 0000000000..0d76652b97 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java @@ -0,0 +1,81 @@ +/* + * 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 java.util.Random; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.reset; + +public class TransactionProcessorTest extends BaseProcessorTest { + + private Random random = new Random(); + private static final String PRODUCER_GROUP = "producerGroup"; + private TransactionProcessor transactionProcessor; + + @Before + public void before() throws Throwable { + super.before(); + this.transactionProcessor = new TransactionProcessor(this.messagingProcessor, this.serviceManager); + } + + @Test + public void testEndTransaction() throws Throwable { + testEndTransaction(MessageSysFlag.TRANSACTION_COMMIT_TYPE, TransactionStatus.COMMIT); + testEndTransaction(MessageSysFlag.TRANSACTION_NOT_TYPE, TransactionStatus.UNKNOWN); + testEndTransaction(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE, TransactionStatus.ROLLBACK); + } + + protected void testEndTransaction(int sysFlag, TransactionStatus transactionStatus) throws Throwable { + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); + doNothing().when(this.messageService).endTransactionOneway(any(), any(), requestHeaderArgumentCaptor.capture(), anyLong()); + + TransactionId transactionId = TransactionId.genByBrokerTransactionId( + "brokerName", + "orgTxId", + random.nextLong(), + random.nextLong() + ); + this.transactionProcessor.endTransaction( + createContext(), + transactionId, + "msgId", + PRODUCER_GROUP, + transactionStatus, + true, + 3000 + ); + + EndTransactionRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); + assertEquals(sysFlag, requestHeader.getCommitOrRollback().intValue()); + assertEquals(transactionId.getBrokerTransactionId(), requestHeader.getTransactionId()); + assertEquals(transactionId.getCommitLogOffset(), requestHeader.getCommitLogOffset().longValue()); + assertEquals(transactionId.getTranStateTableOffset(), requestHeader.getTranStateTableOffset().longValue()); + + reset(this.messageService); + } +} \ No newline at end of file diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java index cb8c9a1844..2f123db45e 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.remoting.netty; public class NettyClientConfig { - private int bootstrapWorkerThreads = 1; /** * Worker thread number */ @@ -44,19 +43,11 @@ public class NettyClientConfig { private boolean useTLS; - private boolean disableCallbackExecutor = false; - private boolean disableNettyWorkerGroup = false; - private int writeBufferHighWaterMark = NettySystemConfig.writeBufferHighWaterMark; private int writeBufferLowWaterMark = NettySystemConfig.writeBufferLowWaterMark; - public int getBootstrapWorkerThreads() { - return bootstrapWorkerThreads; - } - - public void setBootstrapWorkerThreads(int bootstrapWorkerThreads) { - this.bootstrapWorkerThreads = bootstrapWorkerThreads; - } + private boolean disableCallbackExecutor = false; + private boolean disableNettyWorkerGroup = false; public boolean isClientCloseSocketIfTimeout() { return clientCloseSocketIfTimeout; diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index e9bbdc14f8..b19f56fd84 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -24,7 +24,8 @@ import java.util.Map; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; -import org.apache.rocketmq.proxy.service.ServiceManager; +import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.test.util.MQAdminTestUtils; import org.junit.After; import org.junit.Before; @@ -34,16 +35,16 @@ import static org.awaitility.Awaitility.await; public class ClusterGrpcIT extends GrpcBaseIT { - private ServiceManager serviceManager; + private MessagingProcessor messagingProcessor; private GrpcMessagingApplication grpcMessagingApplication; @Before public void setUp() throws Exception { super.setUp(); ConfigurationManager.getProxyConfig().setTransactionHeartbeatPeriodSecond(3); - serviceManager = ServiceManager.createForClusterMode(); - serviceManager.start(); - grpcMessagingApplication = GrpcMessagingApplication.create(serviceManager); + messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); + messagingProcessor.start(); + grpcMessagingApplication = GrpcMessagingApplication.create(messagingProcessor); grpcMessagingApplication.start(); setUpServer(grpcMessagingApplication, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); @@ -55,7 +56,7 @@ public class ClusterGrpcIT extends GrpcBaseIT { @After public void tearDown() throws Exception { - serviceManager.shutdown(); + messagingProcessor.shutdown(); grpcMessagingApplication.shutdown(); shutdown(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 64b4da7a7b..efbda29d54 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -171,7 +171,7 @@ public class GrpcBaseIT extends BaseConf { requestStreamObserver.onNext(TelemetryCommand.newBuilder() .setSettings(clientSettings) .build()); - requestStreamObserver.onCompleted(); + future.whenComplete((settings, throwable) -> requestStreamObserver.onCompleted()); return future; } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 954167e79f..94073ff454 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -21,6 +21,8 @@ import apache.rocketmq.v2.QueryAssignmentResponse; import apache.rocketmq.v2.QueryRouteResponse; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; +import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.service.ServiceManager; import org.junit.After; import org.junit.Before; @@ -28,22 +30,22 @@ import org.junit.Test; public class LocalGrpcIT extends GrpcBaseIT { - private ServiceManager serviceManager; + private MessagingProcessor messagingProcessor; private GrpcMessagingApplication grpcMessagingApplication; @Before public void setUp() throws Exception { super.setUp(); - serviceManager = ServiceManager.createForClusterMode(); - serviceManager.start(); - grpcMessagingApplication = GrpcMessagingApplication.create(serviceManager); + messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); + messagingProcessor.start(); + grpcMessagingApplication = GrpcMessagingApplication.create(messagingProcessor); grpcMessagingApplication.start(); setUpServer(grpcMessagingApplication, ConfigurationManager.getProxyConfig().getGrpcServerPort(), true); } @After public void clean() throws Exception { - serviceManager.shutdown(); + messagingProcessor.shutdown(); grpcMessagingApplication.shutdown(); shutdown(); } From f91a4c0ee283ef915a4e002f7ffa97c6f243c61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A4=AE?= Date: Tue, 17 May 2022 17:27:05 +0800 Subject: [PATCH 176/338] Rename ProxyOutService to ProxyRelayService --- .../grpc/v2/channel/GrpcChannelManager.java | 12 ++++++------ .../proxy/grpc/v2/channel/GrpcClientChannel.java | 10 +++++----- .../proxy/grpc/v2/client/ClientActivity.java | 2 +- .../processor/DefaultMessagingProcessor.java | 5 ++--- .../proxy/processor/MessagingProcessor.java | 4 ++-- .../proxy/service/ClusterServiceManager.java | 12 ++++++------ .../proxy/service/LocalServiceManager.java | 12 ++++++------ .../rocketmq/proxy/service/ServiceManager.java | 4 ++-- .../ClusterProxyRelayService.java} | 4 ++-- .../LocalProxyRelayService.java} | 6 +++--- .../service/{out => relay}/ProxyChannel.java | 16 ++++++++-------- .../service/{out => relay}/ProxyOutResult.java | 2 +- .../ProxyRelayService.java} | 4 ++-- .../rocketmq/proxy/grpc/v2/BaseActivityTest.java | 7 +++---- .../proxy/processor/BaseProcessorTest.java | 6 +++--- 15 files changed, 52 insertions(+), 54 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/{out/ClusterProxyOutService.java => relay/ClusterProxyRelayService.java} (93%) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/{out/LocalProxyOutService.java => relay/LocalProxyRelayService.java} (94%) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/{out => relay}/ProxyChannel.java (91%) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/{out => relay}/ProxyOutResult.java (96%) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/{out/ProxyOutService.java => relay/ProxyRelayService.java} (94%) 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 b5bb417ba6..bb7f4b203f 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 @@ -33,11 +33,11 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.service.out.ProxyOutResult; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; public class GrpcChannelManager implements StartAndShutdown { - private final ProxyOutService proxyOutService; + private final ProxyRelayService proxyRelayService; protected final ConcurrentMap/* clientId */> groupClientIdChannelMap = new ConcurrentHashMap<>(); protected final AtomicLong nonceIdGenerator = new AtomicLong(0); @@ -47,8 +47,8 @@ public class GrpcChannelManager implements StartAndShutdown { new ThreadFactoryImpl("GrpcChannelManager_") ); - public GrpcChannelManager(ProxyOutService proxyOutService) { - this.proxyOutService = proxyOutService; + public GrpcChannelManager(ProxyRelayService proxyRelayService) { + this.proxyRelayService = proxyRelayService; } protected void init() { @@ -63,7 +63,7 @@ public class GrpcChannelManager implements StartAndShutdown { if (clientIdMap == null) { clientIdMap = new ConcurrentHashMap<>(); } - clientIdMap.computeIfAbsent(clientId, clientIdKey -> new GrpcClientChannel(proxyOutService, this, ctx, group, clientId)); + clientIdMap.computeIfAbsent(clientId, clientIdKey -> new GrpcClientChannel(proxyRelayService, this, ctx, group, clientId)); return clientIdMap; }); return getChannel(group, clientId); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 1dbed8eeed..2ec136c5b0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -35,9 +35,9 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; -import org.apache.rocketmq.proxy.service.out.ProxyChannel; -import org.apache.rocketmq.proxy.service.out.ProxyOutResult; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyChannel; +import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -54,8 +54,8 @@ public class GrpcClientChannel extends ProxyChannel { private final String remoteAddress; private final String localAddress; - public GrpcClientChannel(ProxyOutService proxyOutService, GrpcChannelManager grpcChannelManager, Context ctx, String group, String clientId) { - super(proxyOutService, null, new GrpcChannelId(group, clientId)); + public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, Context ctx, String group, String clientId) { + super(proxyRelayService, null, new GrpcChannelId(group, clientId)); this.grpcChannelManager = grpcChannelManager; this.remoteAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS); this.localAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index c0fcdf016e..b707351ed6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -64,7 +64,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.out.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; import org.apache.rocketmq.remoting.protocol.LanguageCode; public class ClientActivity extends AbstractMessingActivity { 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 a590da8ed6..3e5d82c866 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 @@ -40,11 +40,10 @@ import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.common.utils.FutureUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.ServiceManager; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; @@ -216,7 +215,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public ProxyOutService getProxyOutService() { + public ProxyRelayService getProxyOutService() { return this.serviceManager.getProxyOutService(); } 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 3f29fe2f6c..10ac52c1c0 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,7 +37,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; @@ -219,5 +219,5 @@ public interface MessagingProcessor extends StartAndShutdown { String topic ); - ProxyOutService getProxyOutService(); + ProxyRelayService getProxyOutService(); } 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 935f25a8ae..61d8537a92 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 @@ -35,8 +35,8 @@ import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.message.ClusterMessageService; import org.apache.rocketmq.proxy.service.message.MessageService; import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; -import org.apache.rocketmq.proxy.service.out.ClusterProxyOutService; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ClusterProxyRelayService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ClusterTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; @@ -51,7 +51,7 @@ public class ClusterServiceManager extends ServiceManager { private final ConsumerManager consumerManager; private final TopicRouteService topicRouteService; private final MessageService messageService; - private final ProxyOutService proxyOutService; + private final ProxyRelayService proxyRelayService; private final ScheduledExecutorService scheduledExecutorService; private final MQClientAPIFactory mqClientAPIFactory; @@ -72,7 +72,7 @@ public class ClusterServiceManager extends ServiceManager { this.topicRouteService = new ClusterTopicRouteService(rpcHook); this.messageService = new ClusterMessageService(this.topicRouteService, this.mqClientAPIFactory); this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook); - this.proxyOutService = new ClusterProxyOutService(); + this.proxyRelayService = new ClusterProxyRelayService(); this.init(); } @@ -121,8 +121,8 @@ public class ClusterServiceManager extends ServiceManager { } @Override - public ProxyOutService getProxyOutService() { - return this.proxyOutService; + public ProxyRelayService getProxyOutService() { + return this.proxyRelayService; } protected static class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { 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 97549a6eb0..1a57721feb 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 @@ -21,8 +21,8 @@ import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.proxy.service.message.LocalMessageService; import org.apache.rocketmq.proxy.service.message.MessageService; -import org.apache.rocketmq.proxy.service.out.LocalProxyOutService; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.LocalProxyRelayService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.LocalTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.LocalTransactionService; @@ -35,14 +35,14 @@ public class LocalServiceManager extends ServiceManager { private final TopicRouteService topicRouteService; private final MessageService messageService; private final TransactionService transactionService; - private final ProxyOutService proxyOutService; + private final ProxyRelayService proxyRelayService; public LocalServiceManager(BrokerController brokerController, RPCHook rpcHook) { this.brokerController = brokerController; this.messageService = new LocalMessageService(brokerController, rpcHook); this.topicRouteService = new LocalTopicRouteService(brokerController, rpcHook); this.transactionService = new LocalTransactionService(); - this.proxyOutService = new LocalProxyOutService(brokerController); + this.proxyRelayService = new LocalProxyRelayService(brokerController); this.init(); } @@ -77,8 +77,8 @@ public class LocalServiceManager extends ServiceManager { } @Override - public ProxyOutService getProxyOutService() { - return this.proxyOutService; + public ProxyRelayService getProxyOutService() { + return this.proxyRelayService; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java index 820d99444b..273a515dab 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -21,7 +21,7 @@ import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.service.message.MessageService; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.RPCHook; @@ -54,5 +54,5 @@ public abstract class ServiceManager extends AbstractStartAndShutdown { public abstract TransactionService getTransactionService(); - public abstract ProxyOutService getProxyOutService(); + public abstract ProxyRelayService getProxyOutService(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java similarity index 93% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java index e6f8abc192..9b1bba2c79 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ClusterProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.service.out; +package org.apache.rocketmq.proxy.service.relay; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; @@ -26,7 +26,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; /** * not implement yet */ -public class ClusterProxyOutService implements ProxyOutService { +public class ClusterProxyRelayService implements ProxyRelayService { @Override public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index 0a243600f5..e821fb60b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/LocalProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.service.out; +package org.apache.rocketmq.proxy.service.relay; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.BrokerController; @@ -27,11 +27,11 @@ import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class LocalProxyOutService implements ProxyOutService { +public class LocalProxyRelayService implements ProxyRelayService { private final BrokerController brokerController; - public LocalProxyOutService(BrokerController brokerController) { + public LocalProxyRelayService(BrokerController brokerController) { this.brokerController = brokerController; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java similarity index 91% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 1a85a96d65..1dcea7aa37 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.service.out; +package org.apache.rocketmq.proxy.service.relay; import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; @@ -47,16 +47,16 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public abstract class ProxyChannel extends AbstractChannel { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - protected final ProxyOutService proxyOutService; + protected final ProxyRelayService proxyRelayService; - protected ProxyChannel(ProxyOutService proxyOutService, Channel parent) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent) { super(parent); - this.proxyOutService = proxyOutService; + this.proxyRelayService = proxyRelayService; } - protected ProxyChannel(ProxyOutService proxyOutService, Channel parent, ChannelId id) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id) { super(parent, id); - this.proxyOutService = proxyOutService; + this.proxyRelayService = proxyRelayService; } @Override @@ -78,14 +78,14 @@ public abstract class ProxyChannel extends AbstractChannel { case RequestCode.GET_CONSUMER_RUNNING_INFO: { GetConsumerRunningInfoRequestHeader header = (GetConsumerRunningInfoRequestHeader) command.readCustomHeader(); processFuture = this.processGetConsumerRunningInfo(command, header, - this.proxyOutService.processGetConsumerRunningInfo(command, header)); + this.proxyRelayService.processGetConsumerRunningInfo(command, header)); break; } case RequestCode.CONSUME_MESSAGE_DIRECTLY: { ConsumeMessageDirectlyResultRequestHeader header = (ConsumeMessageDirectlyResultRequestHeader) command.readCustomHeader(); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); processFuture = this.processConsumeMessageDirectly(command, header, messageExt, - this.proxyOutService.processConsumeMessageDirectly(command, header)); + this.proxyRelayService.processConsumeMessageDirectly(command, header)); break; } default: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java similarity index 96% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java index efeccbafd1..985481a17f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutResult.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.service.out; +package org.apache.rocketmq.proxy.service.relay; public class ProxyOutResult { private int code; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java similarity index 94% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java index dbe0f13255..9e905d3f5b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/out/ProxyOutService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.rocketmq.proxy.service.out; +package org.apache.rocketmq.proxy.service.relay; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; @@ -23,7 +23,7 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public interface ProxyOutService { +public interface ProxyRelayService { CompletableFuture> processGetConsumerRunningInfo( RemotingCommand command, diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index 2217ce4e7a..c155b382e8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -28,8 +28,7 @@ import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; -import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.junit.Ignore; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -46,7 +45,7 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { @Mock protected GrpcClientSettingsManager grpcClientSettingsManager; @Mock - protected ProxyOutService proxyOutService; + protected ProxyRelayService proxyRelayService; protected static final String REMOTE_ADDR = "192.168.0.1:8080"; protected static final String LOCAL_ADDR = "127.0.0.1:8080"; @@ -58,7 +57,7 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); - when(messagingProcessor.getProxyOutService()).thenReturn(proxyOutService); + when(messagingProcessor.getProxyOutService()).thenReturn(proxyRelayService); } protected Context createContext() { 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 5e0a256e12..29e0ab3379 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 @@ -31,7 +31,7 @@ import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.message.MessageService; -import org.apache.rocketmq.proxy.service.out.ProxyOutService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.junit.Ignore; @@ -61,7 +61,7 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { @Mock protected TransactionService transactionService; @Mock - protected ProxyOutService proxyOutService; + protected ProxyRelayService proxyRelayService; @Mock protected ProducerProcessor producerProcessor; @Mock @@ -78,7 +78,7 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { when(serviceManager.getProducerManager()).thenReturn(producerManager); when(serviceManager.getConsumerManager()).thenReturn(consumerManager); when(serviceManager.getTransactionService()).thenReturn(transactionService); - when(serviceManager.getProxyOutService()).thenReturn(proxyOutService); + when(serviceManager.getProxyOutService()).thenReturn(proxyRelayService); } protected static ProxyContext createContext() { From c04c3185e5891d806fb1d8b0862d97b06cd698ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A4=AE?= Date: Tue, 17 May 2022 17:28:12 +0800 Subject: [PATCH 177/338] Rename ProxyOutResult to ProxyRelayResult --- .../proxy/grpc/v2/channel/GrpcChannelManager.java | 12 ++++++------ .../proxy/grpc/v2/channel/GrpcClientChannel.java | 6 +++--- .../proxy/grpc/v2/client/ClientActivity.java | 14 +++++++------- .../service/relay/ClusterProxyRelayService.java | 4 ++-- .../service/relay/LocalProxyRelayService.java | 6 +++--- .../rocketmq/proxy/service/relay/ProxyChannel.java | 4 ++-- .../{ProxyOutResult.java => ProxyRelayResult.java} | 4 ++-- .../proxy/service/relay/ProxyRelayService.java | 4 ++-- 8 files changed, 27 insertions(+), 27 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/{ProxyOutResult.java => ProxyRelayResult.java} (93%) 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 bb7f4b203f..262c83fd01 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 @@ -33,7 +33,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; public class GrpcChannelManager implements StartAndShutdown { @@ -89,13 +89,13 @@ public class GrpcChannelManager implements StartAndShutdown { return channelRef.get(); } - public String addResponseFuture(CompletableFuture> responseFuture) { + public String addResponseFuture(CompletableFuture> responseFuture) { String nonce = this.nextNonce(); this.resultNonceFutureMap.put(nonce, new ResultFuture<>(responseFuture)); return nonce; } - public CompletableFuture> getAndRemoveResponseFuture(String nonce) { + public CompletableFuture> getAndRemoveResponseFuture(String nonce) { ResultFuture resultFuture = this.resultNonceFutureMap.remove(nonce); if (resultFuture != null) { return resultFuture.future; @@ -120,7 +120,7 @@ public class GrpcChannelManager implements StartAndShutdown { if (System.currentTimeMillis() - resultFuture.createTime > timeOutMs) { resultFuture = this.resultNonceFutureMap.remove(nonce); if (resultFuture != null) { - resultFuture.future.complete(new ProxyOutResult<>(ResponseCode.SYSTEM_BUSY, "call remote timeout", null)); + resultFuture.future.complete(new ProxyRelayResult<>(ResponseCode.SYSTEM_BUSY, "call remote timeout", null)); } } } @@ -137,10 +137,10 @@ public class GrpcChannelManager implements StartAndShutdown { } protected static class ResultFuture { - public CompletableFuture> future; + public CompletableFuture> future; public long createTime = System.currentTimeMillis(); - public ResultFuture(CompletableFuture> future) { + public ResultFuture(CompletableFuture> future) { this.future = future; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 2ec136c5b0..eb3e8c9b47 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -36,7 +36,7 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.service.relay.ProxyChannel; -import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.common.RemotingUtil; @@ -154,7 +154,7 @@ public class GrpcClientChannel extends ProxyChannel { @Override protected CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header, - CompletableFuture> responseFuture) { + CompletableFuture> responseFuture) { if (!header.isJstackEnable()) { return CompletableFuture.completedFuture(null); } @@ -169,7 +169,7 @@ public class GrpcClientChannel extends ProxyChannel { @Override protected CompletableFuture processConsumeMessageDirectly(RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header, - MessageExt messageExt, CompletableFuture> responseFuture) { + MessageExt messageExt, CompletableFuture> responseFuture) { this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() .setVerifyMessageCommand(VerifyMessageCommand.newBuilder() .setNonce(this.grpcChannelManager.addResponseFuture(responseFuture)) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index b707351ed6..854507370b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -64,7 +64,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.relay.ProxyOutResult; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.remoting.protocol.LanguageCode; public class ClientActivity extends AbstractMessingActivity { @@ -247,17 +247,17 @@ public class ClientActivity extends AbstractMessingActivity { protected void reportThreadStackTrace(Context ctx, Status status, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); - CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); if (responseFuture != null) { try { if (status.getCode().equals(Code.OK)) { ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); runningInfo.setJstack(threadStack); - responseFuture.complete(new ProxyOutResult<>(ResponseCode.SUCCESS, "", runningInfo)); + responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, "", runningInfo)); } else if (status.getCode().equals(Code.VERIFY_MESSAGE_FORBIDDEN)) { - responseFuture.complete(new ProxyOutResult<>(ResponseCode.NO_PERMISSION, "forbidden to verify message", null)); + responseFuture.complete(new ProxyRelayResult<>(ResponseCode.NO_PERMISSION, "forbidden to verify message", null)); } else { - responseFuture.complete(new ProxyOutResult<>(ResponseCode.SYSTEM_ERROR, "verify message failed", null)); + responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SYSTEM_ERROR, "verify message failed", null)); } } catch (Throwable t) { responseFuture.completeExceptionally(t); @@ -267,11 +267,11 @@ public class ClientActivity extends AbstractMessingActivity { protected void reportVerifyMessageResult(Context ctx, Status status, VerifyMessageResult request) { String nonce = request.getNonce(); - CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); + CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); if (responseFuture != null) { try { ConsumeMessageDirectlyResult result = this.buildConsumeMessageDirectlyResult(status, request); - responseFuture.complete(new ProxyOutResult<>(ResponseCode.SUCCESS, "", result)); + responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, "", result)); } catch (Throwable t) { responseFuture.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java index 9b1bba2c79..4db1a84540 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java @@ -29,12 +29,12 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ClusterProxyRelayService implements ProxyRelayService { @Override - public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, + public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { return null; } - @Override public CompletableFuture> processConsumeMessageDirectly( + @Override public CompletableFuture> processConsumeMessageDirectly( RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index e821fb60b4..8ecb6988d2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -36,9 +36,9 @@ public class LocalProxyRelayService implements ProxyRelayService { } @Override - public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, + public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { - CompletableFuture> future = new CompletableFuture<>(); + CompletableFuture> future = new CompletableFuture<>(); future.thenAccept(proxyOutResult -> { if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); @@ -59,7 +59,7 @@ public class LocalProxyRelayService implements ProxyRelayService { } @Override - public CompletableFuture> processConsumeMessageDirectly(RemotingCommand command, + public CompletableFuture> processConsumeMessageDirectly(RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 1dcea7aa37..153ffb709f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -116,13 +116,13 @@ public abstract class ProxyChannel extends AbstractChannel { protected abstract CompletableFuture processGetConsumerRunningInfo( RemotingCommand command, GetConsumerRunningInfoRequestHeader header, - CompletableFuture> responseFuture); + CompletableFuture> responseFuture); protected abstract CompletableFuture processConsumeMessageDirectly( RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header, MessageExt messageExt, - CompletableFuture> responseFuture); + CompletableFuture> responseFuture); @Override public ChannelConfig config() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayResult.java similarity index 93% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayResult.java index 985481a17f..95b98d4d6b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyOutResult.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayResult.java @@ -17,12 +17,12 @@ package org.apache.rocketmq.proxy.service.relay; -public class ProxyOutResult { +public class ProxyRelayResult { private int code; private String remark; private T result; - public ProxyOutResult(int code, String remark, T result) { + public ProxyRelayResult(int code, String remark, T result) { this.code = code; this.remark = remark; this.result = result; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java index 9e905d3f5b..1e800206a3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java @@ -25,12 +25,12 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface ProxyRelayService { - CompletableFuture> processGetConsumerRunningInfo( + CompletableFuture> processGetConsumerRunningInfo( RemotingCommand command, GetConsumerRunningInfoRequestHeader header ); - CompletableFuture> processConsumeMessageDirectly( + CompletableFuture> processConsumeMessageDirectly( RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header ); From 1451bf555857030e9132bf180333cebf17d9bb45 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 17 May 2022 17:35:36 +0800 Subject: [PATCH 178/338] [ISSUE #3949] v2 support --- .../grpc/v2/consumer/ReceiveMessageActivity.java | 12 +++++++++++- .../consumer/ReceiveMessageResponseStreamWriter.java | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index bac4e3cc44..27dc411ba9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -31,6 +31,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; 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.GrpcContextConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; @@ -65,6 +66,15 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "no new message"); return; } + + long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); + if (request.getAutoRenew()) { + invisibleTime = Durations.toMillis( + this.grpcClientSettingsManager.getClientSettings(proxyContext.getVal(GrpcContextConstants.CLIENT_ID)) + .getSubscription().getLongPollingTimeout() + ); + } + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); FilterExpression filterExpression = request.getFilterExpression(); @@ -85,7 +95,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { group, topic, request.getBatchSize(), - Durations.toMillis(request.getInvisibleDuration()), + invisibleTime, pollTime, ConsumeInitMode.MAX, subscriptionData, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java index 6a94f49848..52514ef0ef 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -56,7 +56,7 @@ public class ReceiveMessageResponseStreamWriter { case FOUND: if (messageFoundList.isEmpty()) { streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no new message")) + .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no match message")) .build()); } else { streamObserver.onNext(ReceiveMessageResponse.newBuilder() From fc1b26706ae291a272bd5cd52e5eb0b1fb050007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A4=AE?= Date: Tue, 17 May 2022 17:40:06 +0800 Subject: [PATCH 179/338] Add ServiceManagerFactory --- .../processor/DefaultMessagingProcessor.java | 5 ++- .../proxy/service/ClusterServiceManager.java | 3 +- .../proxy/service/LocalServiceManager.java | 3 +- .../proxy/service/ServiceManager.java | 35 ++++------------- .../proxy/service/ServiceManagerFactory.java | 38 +++++++++++++++++++ 5 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManagerFactory.java 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 3e5d82c866..885b5d311b 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 @@ -43,6 +43,7 @@ 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.ServiceManager; +import org.apache.rocketmq.proxy.service.ServiceManagerFactory; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -94,7 +95,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } public static DefaultMessagingProcessor createForLocalMode(BrokerController brokerController, RPCHook rpcHook) { - return new DefaultMessagingProcessor(ServiceManager.createForLocalMode(brokerController, rpcHook)); + return new DefaultMessagingProcessor(ServiceManagerFactory.createForLocalMode(brokerController, rpcHook)); } public static DefaultMessagingProcessor createForClusterMode() { @@ -102,7 +103,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } public static DefaultMessagingProcessor createForClusterMode(RPCHook rpcHook) { - return new DefaultMessagingProcessor(ServiceManager.createForClusterMode(rpcHook)); + return new DefaultMessagingProcessor(ServiceManagerFactory.createForClusterMode(rpcHook)); } protected void init() { 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 61d8537a92..1fda36c9f3 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 @@ -29,6 +29,7 @@ import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; @@ -43,7 +44,7 @@ import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.RPCHook; -public class ClusterServiceManager extends ServiceManager { +public class ClusterServiceManager extends AbstractStartAndShutdown implements ServiceManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ClusterTransactionService clusterTransactionService; 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 1a57721feb..c2438c939c 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 @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.service; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.service.message.LocalMessageService; import org.apache.rocketmq.proxy.service.message.MessageService; import org.apache.rocketmq.proxy.service.relay.LocalProxyRelayService; @@ -29,7 +30,7 @@ import org.apache.rocketmq.proxy.service.transaction.LocalTransactionService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.RPCHook; -public class LocalServiceManager extends ServiceManager { +public class LocalServiceManager extends AbstractStartAndShutdown implements ServiceManager { private final BrokerController brokerController; private final TopicRouteService topicRouteService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java index 273a515dab..a51a1a1307 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -16,43 +16,24 @@ */ package org.apache.rocketmq.proxy.service; -import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.message.MessageService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; -import org.apache.rocketmq.remoting.RPCHook; -public abstract class ServiceManager extends AbstractStartAndShutdown { +public interface ServiceManager extends StartAndShutdown { + MessageService getMessageService(); - public static ServiceManager createForLocalMode(BrokerController brokerController) { - return createForLocalMode(brokerController, null); - } + TopicRouteService getTopicRouteService(); - public static ServiceManager createForLocalMode(BrokerController brokerController, RPCHook rpcHook) { - return new LocalServiceManager(brokerController, rpcHook); - } + ProducerManager getProducerManager(); - public static ServiceManager createForClusterMode() { - return createForClusterMode(null); - } + ConsumerManager getConsumerManager(); - public static ServiceManager createForClusterMode(RPCHook rpcHook) { - return new ClusterServiceManager(rpcHook); - } + TransactionService getTransactionService(); - public abstract MessageService getMessageService(); - - public abstract TopicRouteService getTopicRouteService(); - - public abstract ProducerManager getProducerManager(); - - public abstract ConsumerManager getConsumerManager(); - - public abstract TransactionService getTransactionService(); - - public abstract ProxyRelayService getProxyOutService(); + ProxyRelayService getProxyOutService(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManagerFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManagerFactory.java new file mode 100644 index 0000000000..c186752788 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManagerFactory.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.proxy.service; + +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.remoting.RPCHook; + +public class ServiceManagerFactory { + public static ServiceManager createForLocalMode(BrokerController brokerController) { + return createForLocalMode(brokerController, null); + } + + public static ServiceManager createForLocalMode(BrokerController brokerController, RPCHook rpcHook) { + return new LocalServiceManager(brokerController, rpcHook); + } + + public static ServiceManager createForClusterMode() { + return createForClusterMode(null); + } + + public static ServiceManager createForClusterMode(RPCHook rpcHook) { + return new ClusterServiceManager(rpcHook); + } +} From 418ced880e86ef1c8860695a1bf7b5cd8c6a0bec Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 17 May 2022 19:00:51 +0800 Subject: [PATCH 180/338] [ISSUE #3949] improve readability. --- .../rocketmq/proxy/processor/DefaultMessagingProcessor.java | 2 +- .../apache/rocketmq/proxy/service/ClusterServiceManager.java | 2 +- .../org/apache/rocketmq/proxy/service/LocalServiceManager.java | 2 +- .../java/org/apache/rocketmq/proxy/service/ServiceManager.java | 2 +- .../org/apache/rocketmq/proxy/processor/BaseProcessorTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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 885b5d311b..0269b752be 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 @@ -217,7 +217,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen @Override public ProxyRelayService getProxyOutService() { - return this.serviceManager.getProxyOutService(); + return this.serviceManager.getProxyRelayService(); } } 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 1fda36c9f3..de6eda54a2 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 @@ -122,7 +122,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S } @Override - public ProxyRelayService getProxyOutService() { + public ProxyRelayService getProxyRelayService() { return this.proxyRelayService; } 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 c2438c939c..36a798d273 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 @@ -78,7 +78,7 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser } @Override - public ProxyRelayService getProxyOutService() { + public ProxyRelayService getProxyRelayService() { return this.proxyRelayService; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java index a51a1a1307..c80811f469 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -35,5 +35,5 @@ public interface ServiceManager extends StartAndShutdown { TransactionService getTransactionService(); - ProxyRelayService getProxyOutService(); + ProxyRelayService getProxyRelayService(); } 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 29e0ab3379..31954705b7 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 @@ -78,7 +78,7 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { when(serviceManager.getProducerManager()).thenReturn(producerManager); when(serviceManager.getConsumerManager()).thenReturn(consumerManager); when(serviceManager.getTransactionService()).thenReturn(transactionService); - when(serviceManager.getProxyOutService()).thenReturn(proxyRelayService); + when(serviceManager.getProxyRelayService()).thenReturn(proxyRelayService); } protected static ProxyContext createContext() { From 7c322c8ab8dfbdd55cb63e250e547b84b751aa3c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 10 May 2022 15:26:39 +0800 Subject: [PATCH 181/338] [ISSUE #3949] support topic message type --- .../attribute/AbstractRangeAttribute.java | 47 ++++++++++ .../common/attribute/IntRangeAttribute.java | 29 ++++++ .../common/attribute/LongRangeAttribute.java | 23 +---- .../common/constant/TopicMessageTypeName.java | 52 ++++++++++ .../rocketmq/proxy/config/ProxyConfig.java | 55 +++++++++++ .../proxy/connector/TopicConfigCache.java | 94 +++++++++++++++++++ 6 files changed, 281 insertions(+), 19 deletions(-) create mode 100644 common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java create mode 100644 common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java new file mode 100644 index 0000000000..7b773884e0 --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.common.attribute; + +import static java.lang.String.format; + +public abstract class AbstractRangeAttribute> extends Attribute { + + protected final T min; + protected final T max; + protected final T defaultValue; + + public AbstractRangeAttribute(String name, boolean changeable, T min, T max, T defaultValue) { + super(name, changeable); + this.min = min; + this.max = max; + this.defaultValue = defaultValue; + } + + protected abstract T parse(String value); + + @Override + public void verify(String value) { + T l = parse(value); + if (l.compareTo(min) < 0 || l.compareTo(max) > 0) { + throw new RuntimeException(format("value is not in range(%s, %s)", min, max)); + } + } + + public T getDefaultValue() { + return defaultValue; + } +} diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java new file mode 100644 index 0000000000..d55a3124ff --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.common.attribute; + +public class IntRangeAttribute extends AbstractRangeAttribute { + + public IntRangeAttribute(String name, boolean changeable, int min, int max, int defaultValue) { + super(name, changeable, min, max, defaultValue); + } + + @Override + protected Integer parse(String value) { + return Integer.parseInt(value); + } +} diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java index eeeda72153..f4ccbc561e 100644 --- a/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java +++ b/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java @@ -16,29 +16,14 @@ */ package org.apache.rocketmq.common.attribute; -import static java.lang.String.format; - -public class LongRangeAttribute extends Attribute { - private final long min; - private final long max; - private final long defaultValue; +public class LongRangeAttribute extends AbstractRangeAttribute { public LongRangeAttribute(String name, boolean changeable, long min, long max, long defaultValue) { - super(name, changeable); - this.min = min; - this.max = max; - this.defaultValue = defaultValue; + super(name, changeable, min, max, defaultValue); } @Override - public void verify(String value) { - long l = Long.parseLong(value); - if (l < min || l > max) { - throw new RuntimeException(format("value is not in range(%d, %d)", min, max)); - } - } - - public long getDefaultValue() { - return defaultValue; + protected Long parse(String value) { + return Long.parseLong(value); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java b/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java new file mode 100644 index 0000000000..0050acee0f --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.common.constant; + +public class TopicMessageTypeName { + public static final int INDEX_TRANSACTION = 4; + public static final int INDEX_DELAY = 3; + public static final int INDEX_FIFO = 2; + public static final int INDEX_NORMAL = 1; + + public static final int TRANSACTION = 0x1 << INDEX_TRANSACTION; + public static final int DELAY = 0x1 << INDEX_DELAY; + public static final int FIFO = 0x1 << INDEX_FIFO; + public static final int NORMAL = 0x1 << INDEX_NORMAL; + public static final int UNSPECIFIED = 0; + + public static final int ALL = NORMAL | FIFO | DELAY | TRANSACTION; + + public static boolean isUnspecified(final int type) { + return type == UNSPECIFIED; + } + + public static boolean isNormal(final int type) { + return (type & NORMAL) == NORMAL; + } + + public static boolean isFifo(final int type) { + return (type & FIFO) == FIFO; + } + + public static boolean isDelay(final int type) { + return (type & DELAY) == DELAY; + } + + public static boolean isTransaction(final int type) { + return (type & TRANSACTION) == TRANSACTION; + } +} 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 4ccc8bc57f..1eb5ab7d66 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 @@ -79,6 +79,13 @@ public class ProxyConfig { private int topicRouteServiceThreadPoolNums = PROCESSOR_NUMBER; private int topicRouteServiceThreadPoolQueueCapacity = 5000; + private int topicConfigCacheExpiredInSeconds = 20; + private int topicConfigCacheExecutorThreadNum = 3; + private int topicConfigCacheExecutorQueueCapacity = 1000; + private int topicConfigCacheMaxNum = 20000; + private int topicConfigThreadPoolNums = 36; + private int topicConfigThreadPoolQueueCapacity = 50000; + private int transactionHeartbeatThreadPoolNums = 20; private int transactionHeartbeatThreadPoolQueueCapacity = 200; private int transactionHeartbeatPeriodSecond = 20; @@ -400,6 +407,54 @@ public class ProxyConfig { this.topicRouteServiceThreadPoolQueueCapacity = topicRouteServiceThreadPoolQueueCapacity; } + public int getTopicConfigCacheExpiredInSeconds() { + return topicConfigCacheExpiredInSeconds; + } + + public void setTopicConfigCacheExpiredInSeconds(int topicConfigCacheExpiredInSeconds) { + this.topicConfigCacheExpiredInSeconds = topicConfigCacheExpiredInSeconds; + } + + public int getTopicConfigCacheExecutorThreadNum() { + return topicConfigCacheExecutorThreadNum; + } + + public void setTopicConfigCacheExecutorThreadNum(int topicConfigCacheExecutorThreadNum) { + this.topicConfigCacheExecutorThreadNum = topicConfigCacheExecutorThreadNum; + } + + public int getTopicConfigCacheExecutorQueueCapacity() { + return topicConfigCacheExecutorQueueCapacity; + } + + public void setTopicConfigCacheExecutorQueueCapacity(int topicConfigCacheExecutorQueueCapacity) { + this.topicConfigCacheExecutorQueueCapacity = topicConfigCacheExecutorQueueCapacity; + } + + public int getTopicConfigCacheMaxNum() { + return topicConfigCacheMaxNum; + } + + public void setTopicConfigCacheMaxNum(int topicConfigCacheMaxNum) { + this.topicConfigCacheMaxNum = topicConfigCacheMaxNum; + } + + public int getTopicConfigThreadPoolNums() { + return topicConfigThreadPoolNums; + } + + public void setTopicConfigThreadPoolNums(int topicConfigThreadPoolNums) { + this.topicConfigThreadPoolNums = topicConfigThreadPoolNums; + } + + public int getTopicConfigThreadPoolQueueCapacity() { + return topicConfigThreadPoolQueueCapacity; + } + + public void setTopicConfigThreadPoolQueueCapacity(int topicConfigThreadPoolQueueCapacity) { + this.topicConfigThreadPoolQueueCapacity = topicConfigThreadPoolQueueCapacity; + } + public int getTransactionHeartbeatThreadPoolNums() { return transactionHeartbeatThreadPoolNums; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java new file mode 100644 index 0000000000..c4ad518e43 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java @@ -0,0 +1,94 @@ +/* + * 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.connector; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.Optional; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.AbstractCacheLoader; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; +import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; + +public class TopicConfigCache { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + private final TopicRouteCache topicRouteCache; + private final ThreadPoolExecutor cacheRefreshExecutor; + private final LoadingCache topicConfigCache; + + private final DefaultForwardClient defaultClient; + + public TopicConfigCache(TopicRouteCache topicRouteCache, DefaultForwardClient client) { + this.topicRouteCache = topicRouteCache; + this.defaultClient = client; + + ProxyConfig config = ConfigurationManager.getProxyConfig(); + this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( + config.getTopicConfigThreadPoolNums(), + config.getTopicConfigThreadPoolNums(), + 1000 * 60, + TimeUnit.MILLISECONDS, + "TopicConfigCacheRefresh", + config.getTopicConfigThreadPoolQueueCapacity() + ); + this.topicConfigCache = CacheBuilder.newBuilder() + .maximumSize(config.getTopicConfigCacheMaxNum()) + .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) + .build(new TopicConfigCacheLoader()); + } + + public TopicConfigAndQueueMapping getTopicConfigAndQueueMapping(String topic) throws Exception { + return topicConfigCache.get(topic); + } + + protected class TopicConfigCacheLoader extends AbstractCacheLoader { + + public TopicConfigCacheLoader() { + super(cacheRefreshExecutor); + } + + @Override + protected TopicConfigAndQueueMapping getDirectly(String topic) throws Exception { + MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topic); + Optional brokerDataOptional = messageQueueWrapper.getTopicRouteData().getBrokerDatas().stream().findAny(); + if (!brokerDataOptional.isPresent()) { + throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, + "No topic route info in name server for the topic: " + topic); + } + + String brokerAddress = brokerDataOptional.get().selectBrokerAddr(); + return defaultClient.getTopicConfig(brokerAddress, topic); + } + + @Override + protected void onErr(String key, Exception e) { + log.error("load topic config failed. topic:{}", key, e); + } + } +} From cfc6217c97697be413e87507290bd991f88ce02d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 10 May 2022 16:11:28 +0800 Subject: [PATCH 182/338] [ISSUE #3949] Remove unused class --- .../rocketmq/common/TopicAttributes.java | 1 - .../attribute/AbstractRangeAttribute.java | 47 ----------------- .../common/attribute/IntRangeAttribute.java | 29 ----------- .../common/attribute/LongRangeAttribute.java | 23 ++++++-- .../common/constant/TopicMessageTypeName.java | 52 ------------------- 5 files changed, 19 insertions(+), 133 deletions(-) delete mode 100644 common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java delete mode 100644 common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java delete mode 100644 common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java diff --git a/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java b/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java index 8c7dd0ead3..5ac1712985 100644 --- a/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java +++ b/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java @@ -42,6 +42,5 @@ public class TopicAttributes { static { ALL = new HashMap<>(); ALL.put(QUEUE_TYPE_ATTRIBUTE.getName(), QUEUE_TYPE_ATTRIBUTE); - ALL.put(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), TOPIC_MESSAGE_TYPE_ATTRIBUTE); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java deleted file mode 100644 index 7b773884e0..0000000000 --- a/common/src/main/java/org/apache/rocketmq/common/attribute/AbstractRangeAttribute.java +++ /dev/null @@ -1,47 +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.common.attribute; - -import static java.lang.String.format; - -public abstract class AbstractRangeAttribute> extends Attribute { - - protected final T min; - protected final T max; - protected final T defaultValue; - - public AbstractRangeAttribute(String name, boolean changeable, T min, T max, T defaultValue) { - super(name, changeable); - this.min = min; - this.max = max; - this.defaultValue = defaultValue; - } - - protected abstract T parse(String value); - - @Override - public void verify(String value) { - T l = parse(value); - if (l.compareTo(min) < 0 || l.compareTo(max) > 0) { - throw new RuntimeException(format("value is not in range(%s, %s)", min, max)); - } - } - - public T getDefaultValue() { - return defaultValue; - } -} diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java deleted file mode 100644 index d55a3124ff..0000000000 --- a/common/src/main/java/org/apache/rocketmq/common/attribute/IntRangeAttribute.java +++ /dev/null @@ -1,29 +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.common.attribute; - -public class IntRangeAttribute extends AbstractRangeAttribute { - - public IntRangeAttribute(String name, boolean changeable, int min, int max, int defaultValue) { - super(name, changeable, min, max, defaultValue); - } - - @Override - protected Integer parse(String value) { - return Integer.parseInt(value); - } -} diff --git a/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java b/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java index f4ccbc561e..eeeda72153 100644 --- a/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java +++ b/common/src/main/java/org/apache/rocketmq/common/attribute/LongRangeAttribute.java @@ -16,14 +16,29 @@ */ package org.apache.rocketmq.common.attribute; -public class LongRangeAttribute extends AbstractRangeAttribute { +import static java.lang.String.format; + +public class LongRangeAttribute extends Attribute { + private final long min; + private final long max; + private final long defaultValue; public LongRangeAttribute(String name, boolean changeable, long min, long max, long defaultValue) { - super(name, changeable, min, max, defaultValue); + super(name, changeable); + this.min = min; + this.max = max; + this.defaultValue = defaultValue; } @Override - protected Long parse(String value) { - return Long.parseLong(value); + public void verify(String value) { + long l = Long.parseLong(value); + if (l < min || l > max) { + throw new RuntimeException(format("value is not in range(%d, %d)", min, max)); + } + } + + public long getDefaultValue() { + return defaultValue; } } diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java b/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java deleted file mode 100644 index 0050acee0f..0000000000 --- a/common/src/main/java/org/apache/rocketmq/common/constant/TopicMessageTypeName.java +++ /dev/null @@ -1,52 +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.common.constant; - -public class TopicMessageTypeName { - public static final int INDEX_TRANSACTION = 4; - public static final int INDEX_DELAY = 3; - public static final int INDEX_FIFO = 2; - public static final int INDEX_NORMAL = 1; - - public static final int TRANSACTION = 0x1 << INDEX_TRANSACTION; - public static final int DELAY = 0x1 << INDEX_DELAY; - public static final int FIFO = 0x1 << INDEX_FIFO; - public static final int NORMAL = 0x1 << INDEX_NORMAL; - public static final int UNSPECIFIED = 0; - - public static final int ALL = NORMAL | FIFO | DELAY | TRANSACTION; - - public static boolean isUnspecified(final int type) { - return type == UNSPECIFIED; - } - - public static boolean isNormal(final int type) { - return (type & NORMAL) == NORMAL; - } - - public static boolean isFifo(final int type) { - return (type & FIFO) == FIFO; - } - - public static boolean isDelay(final int type) { - return (type & DELAY) == DELAY; - } - - public static boolean isTransaction(final int type) { - return (type & TRANSACTION) == TRANSACTION; - } -} From 172d610dc79f5b563d1286f0fa75fdf72744a10f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 10 May 2022 19:22:33 +0800 Subject: [PATCH 183/338] [ISSUE #3949] Add enableTopicMessageTypeCheck --- .../org/apache/rocketmq/proxy/config/ProxyConfig.java | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 1eb5ab7d66..ead79f5228 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 @@ -95,6 +95,8 @@ public class ProxyConfig { private boolean enableACL = false; + private boolean enableTopicMessageTypeCheck = true; + public boolean isEnablePrintJstack() { return enablePrintJstack; } @@ -502,4 +504,12 @@ public class ProxyConfig { public void setEnableACL(boolean enableACL) { this.enableACL = enableACL; } + + public boolean isEnableTopicMessageTypeCheck() { + return enableTopicMessageTypeCheck; + } + + public void setEnableTopicMessageTypeCheck(boolean enableTopicMessageTypeCheck) { + this.enableTopicMessageTypeCheck = enableTopicMessageTypeCheck; + } } From 966672ab2d4427712a370331511dabb4e8b2c58f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 17 May 2022 20:45:37 +0800 Subject: [PATCH 184/338] [ISSUE #3949] Add MetadataService --- .../proxy/connector/TopicConfigCache.java | 94 ------------------- .../proxy/service/ClusterServiceManager.java | 30 ++++-- .../proxy/service/LocalServiceManager.java | 24 ++++- .../proxy/service/ServiceManager.java | 3 + .../metadata/AbstractMetadataService.java | 69 ++++++++++++++ .../metadata/ClusterMetadataService.java | 85 +++++++++++++++++ .../metadata/LocalMetadataService.java | 68 ++++++++++++++ .../service/metadata/MetadataService.java | 24 +++++ .../route/ClusterTopicRouteService.java | 6 +- .../service/route/LocalTopicRouteService.java | 6 +- .../service/route/TopicRouteService.java | 12 +-- 11 files changed, 303 insertions(+), 118 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java b/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java deleted file mode 100644 index c4ad518e43..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/connector/TopicConfigCache.java +++ /dev/null @@ -1,94 +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.proxy.connector; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.LoadingCache; -import java.util.Optional; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.route.BrokerData; -import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; -import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.AbstractCacheLoader; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.connector.route.MessageQueueWrapper; -import org.apache.rocketmq.proxy.connector.route.TopicRouteCache; - -public class TopicConfigCache { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - private final TopicRouteCache topicRouteCache; - private final ThreadPoolExecutor cacheRefreshExecutor; - private final LoadingCache topicConfigCache; - - private final DefaultForwardClient defaultClient; - - public TopicConfigCache(TopicRouteCache topicRouteCache, DefaultForwardClient client) { - this.topicRouteCache = topicRouteCache; - this.defaultClient = client; - - ProxyConfig config = ConfigurationManager.getProxyConfig(); - this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( - config.getTopicConfigThreadPoolNums(), - config.getTopicConfigThreadPoolNums(), - 1000 * 60, - TimeUnit.MILLISECONDS, - "TopicConfigCacheRefresh", - config.getTopicConfigThreadPoolQueueCapacity() - ); - this.topicConfigCache = CacheBuilder.newBuilder() - .maximumSize(config.getTopicConfigCacheMaxNum()) - .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) - .build(new TopicConfigCacheLoader()); - } - - public TopicConfigAndQueueMapping getTopicConfigAndQueueMapping(String topic) throws Exception { - return topicConfigCache.get(topic); - } - - protected class TopicConfigCacheLoader extends AbstractCacheLoader { - - public TopicConfigCacheLoader() { - super(cacheRefreshExecutor); - } - - @Override - protected TopicConfigAndQueueMapping getDirectly(String topic) throws Exception { - MessageQueueWrapper messageQueueWrapper = topicRouteCache.getMessageQueue(topic); - Optional brokerDataOptional = messageQueueWrapper.getTopicRouteData().getBrokerDatas().stream().findAny(); - if (!brokerDataOptional.isPresent()) { - throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, - "No topic route info in name server for the topic: " + topic); - } - - String brokerAddress = brokerDataOptional.get().selectBrokerAddr(); - return defaultClient.getTopicConfig(brokerAddress, topic); - } - - @Override - protected void onErr(String key, Exception e) { - log.error("load topic config failed. topic:{}", key, e); - } - } -} 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 de6eda54a2..74b0052b03 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 @@ -32,12 +32,14 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; 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.proxy.service.mqclient.DoNothingClientRemotingProcessor; import org.apache.rocketmq.proxy.service.relay.ClusterProxyRelayService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.ClusterTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; @@ -53,9 +55,11 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S private final TopicRouteService topicRouteService; private final MessageService messageService; private final ProxyRelayService proxyRelayService; + private final MetadataService metadataService; private final ScheduledExecutorService scheduledExecutorService; - private final MQClientAPIFactory mqClientAPIFactory; + private final MQClientAPIFactory messagingClientAPIFactory; + private final MQClientAPIFactory operationClientAPIFactory; public ClusterServiceManager(RPCHook rpcHook) { this.scheduledExecutorService = Executors.newScheduledThreadPool(3); @@ -63,17 +67,25 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - this.mqClientAPIFactory = new MQClientAPIFactory( + this.messagingClientAPIFactory = new MQClientAPIFactory( "CLUSTER_MQ_CLIENT_", proxyConfig.getRocketmqMQClientNum(), new DoNothingClientRemotingProcessor(null), rpcHook, scheduledExecutorService); + this.operationClientAPIFactory = new MQClientAPIFactory( + "TopicRouteServiceClient_", + 1, + new DoNothingClientRemotingProcessor(null), + rpcHook, + this.scheduledExecutorService + ); - this.topicRouteService = new ClusterTopicRouteService(rpcHook); - this.messageService = new ClusterMessageService(this.topicRouteService, this.mqClientAPIFactory); + this.topicRouteService = new ClusterTopicRouteService(operationClientAPIFactory); + this.messageService = new ClusterMessageService(this.topicRouteService, this.messagingClientAPIFactory); this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook); this.proxyRelayService = new ClusterProxyRelayService(); + this.metadataService = new ClusterMetadataService(topicRouteService, operationClientAPIFactory); this.init(); } @@ -91,7 +103,8 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S }, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS); this.appendShutdown(scheduledExecutorService::shutdown); - this.appendStartAndShutdown(this.mqClientAPIFactory); + this.appendStartAndShutdown(this.messagingClientAPIFactory); + this.appendStartAndShutdown(this.operationClientAPIFactory); this.appendStartAndShutdown(this.topicRouteService); this.appendStartAndShutdown(this.clusterTransactionService); } @@ -126,6 +139,11 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S return this.proxyRelayService; } + @Override + public MetadataService getMetadataService() { + return this.metadataService; + } + protected static class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { @Override 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 36a798d273..c55d0acb87 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,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service; +import java.util.concurrent.Executors; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; @@ -24,6 +25,10 @@ import org.apache.rocketmq.proxy.service.message.LocalMessageService; import org.apache.rocketmq.proxy.service.message.MessageService; import org.apache.rocketmq.proxy.service.relay.LocalProxyRelayService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; +import org.apache.rocketmq.proxy.service.metadata.LocalMetadataService; +import org.apache.rocketmq.proxy.service.metadata.MetadataService; +import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.LocalTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.LocalTransactionService; @@ -37,18 +42,29 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser private final MessageService messageService; private final TransactionService transactionService; private final ProxyRelayService proxyRelayService; + private final MetadataService metadataService; + + private final MQClientAPIFactory mqClientAPIFactory; public LocalServiceManager(BrokerController brokerController, RPCHook rpcHook) { this.brokerController = brokerController; this.messageService = new LocalMessageService(brokerController, rpcHook); - this.topicRouteService = new LocalTopicRouteService(brokerController, rpcHook); + this.mqClientAPIFactory = new MQClientAPIFactory( + "TopicRouteServiceClient_", + 1, + new DoNothingClientRemotingProcessor(null), + rpcHook, + Executors.newSingleThreadScheduledExecutor() + ); + this.topicRouteService = new LocalTopicRouteService(brokerController, mqClientAPIFactory); this.transactionService = new LocalTransactionService(); this.proxyRelayService = new LocalProxyRelayService(brokerController); - + this.metadataService = new LocalMetadataService(brokerController); this.init(); } protected void init() { + this.appendStartAndShutdown(this.mqClientAPIFactory); this.appendStartAndShutdown(this.topicRouteService); } @@ -82,4 +98,8 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser return this.proxyRelayService; } + @Override + public MetadataService getMetadataService() { + return this.metadataService; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java index c80811f469..6a4f1cf371 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -21,6 +21,7 @@ import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.message.MessageService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; +import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; @@ -36,4 +37,6 @@ public interface ServiceManager extends StartAndShutdown { TransactionService getTransactionService(); ProxyRelayService getProxyRelayService(); + + MetadataService getMetadataService(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java new file mode 100644 index 0000000000..e6ca6bdfc1 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.metadata; + +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.AbstractCacheLoader; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; + +public abstract class AbstractMetadataService extends AbstractStartAndShutdown implements MetadataService { + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected final ThreadPoolExecutor cacheRefreshExecutor; + + public AbstractMetadataService() { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( + config.getTopicConfigThreadPoolNums(), + config.getTopicConfigThreadPoolNums(), + 1000 * 60, + TimeUnit.MILLISECONDS, + "MetadataCacheRefresh", + config.getTopicConfigThreadPoolQueueCapacity() + ); + } + + public abstract TopicMessageType getTopicMessageType(String topic); + + protected abstract class AbstractTopicConfigCacheLoader extends AbstractCacheLoader { + + public AbstractTopicConfigCacheLoader() { + super(cacheRefreshExecutor); + } + + protected abstract TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception; + + @Override + public TopicConfigAndQueueMapping getDirectly(String topic) throws Exception { + return loadTopicConfig(topic); + } + + @Override + protected void onErr(String key, Exception e) { + log.error("load topic config failed. topic:{}", key, e); + } + } +} 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 new file mode 100644 index 0000000000..52acefe127 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataService.java @@ -0,0 +1,85 @@ +/* + * 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.service.metadata; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; + +public class ClusterMetadataService extends AbstractMetadataService { + private final LoadingCache topicCache; + private TopicRouteService topicRouteService; + private final static TopicConfigAndQueueMapping EMPTY_TOPIC_CONFIG = new TopicConfigAndQueueMapping(); + + public ClusterMetadataService(TopicRouteService topicRouteService, MQClientAPIFactory mqClientAPIFactory) { + this.topicRouteService = topicRouteService; + ProxyConfig config = ConfigurationManager.getProxyConfig(); + this.topicCache = CacheBuilder.newBuilder() + .maximumSize(config.getTopicRouteCacheMaxNum()) + .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) + .build(new ClusterTopicConfigCacheLoader(mqClientAPIFactory)); + } + + @Override public TopicMessageType getTopicMessageType(String topic) { + TopicConfigAndQueueMapping topicConfigAndQueueMapping; + try { + topicConfigAndQueueMapping = topicCache.get(topic); + } catch (Exception e) { + return TopicMessageType.UNSPECIFIED; + } + if (topicConfigAndQueueMapping.equals(EMPTY_TOPIC_CONFIG)) { + return TopicMessageType.UNSPECIFIED; + } + return topicConfigAndQueueMapping.getTopicMessageType(); + } + + protected class ClusterTopicConfigCacheLoader extends AbstractTopicConfigCacheLoader { + private final MQClientAPIFactory mqClientAPIFactory; + + public ClusterTopicConfigCacheLoader(MQClientAPIFactory mqClientAPIFactory) { + this.mqClientAPIFactory = mqClientAPIFactory; + } + + @Override protected TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception { + try { + Optional brokerDataOptional = topicRouteService.getAllMessageQueueView(topic).getTopicRouteData().getBrokerDatas().stream().findAny(); + if (brokerDataOptional.isPresent()) { + String brokerAddress = topicRouteService.getBrokerAddr(brokerDataOptional.get().getBrokerName()); + return this.mqClientAPIFactory.getClient().getTopicConfig(brokerAddress, topic, 1000L); + } + return EMPTY_TOPIC_CONFIG; + } catch (MQClientException e) { + if (TopicRouteHelper.isTopicNotExistError(e)) { + log.warn("topic is not exist", e); + return EMPTY_TOPIC_CONFIG; + } + throw e; + } + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java new file mode 100644 index 0000000000..7bf0ece856 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.metadata; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; + +public class LocalMetadataService extends AbstractMetadataService { + private final LoadingCache topicCache; + + public LocalMetadataService(BrokerController brokerController) { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + + this.topicCache = CacheBuilder.newBuilder() + .maximumSize(config.getTopicRouteCacheMaxNum()) + .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) + .build(new LocalTopicConfigCacheLoader(brokerController)); + } + + @Override + public TopicMessageType getTopicMessageType(String topic) { + try { + TopicConfigAndQueueMapping topicConfigAndQueueMapping = topicCache.get(topic); + if (topicConfigAndQueueMapping == null) { + return TopicMessageType.UNSPECIFIED; + } + return topicConfigAndQueueMapping.getTopicMessageType(); + } catch (Exception e) { + log.error("getTopicMessageType error", topic, e); + return TopicMessageType.UNSPECIFIED; + } + } + + protected class LocalTopicConfigCacheLoader extends AbstractTopicConfigCacheLoader { + private final BrokerController brokerController; + + public LocalTopicConfigCacheLoader(BrokerController brokerController) { + this.brokerController = brokerController; + } + + @Override protected TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception { + TopicConfig topicConfig = brokerController.getTopicConfigManager().selectTopicConfig(topic); + return new TopicConfigAndQueueMapping(topicConfig, null); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java new file mode 100644 index 0000000000..a87ec1484f --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java @@ -0,0 +1,24 @@ +/* + * 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.service.metadata; + +import org.apache.rocketmq.common.attribute.TopicMessageType; + +public interface MetadataService { + TopicMessageType getTopicMessageType(String topic); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java index de058db13c..94d7dbdd5f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteService.java @@ -21,12 +21,12 @@ import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.Address; -import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; public class ClusterTopicRouteService extends TopicRouteService { - public ClusterTopicRouteService(RPCHook rpcHook) { - super(rpcHook); + public ClusterTopicRouteService(MQClientAPIFactory mqClientAPIFactory) { + super(mqClientAPIFactory); } @Override 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 87d9078997..5da75cea08 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 @@ -29,7 +29,7 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; public class LocalTopicRouteService extends TopicRouteService { @@ -37,8 +37,8 @@ public class LocalTopicRouteService extends TopicRouteService { private final List brokerDataList; private final int grpcPort; - public LocalTopicRouteService(BrokerController brokerController, RPCHook rpcHook) { - super(rpcHook); + public LocalTopicRouteService(BrokerController brokerController, MQClientAPIFactory mqClientAPIFactory) { + super(mqClientAPIFactory); this.brokerController = brokerController; BrokerConfig brokerConfig = this.brokerController.getBrokerConfig(); HashMap brokerAddrs = new HashMap<>(); 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 aa7e5ec359..c800abfa1a 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 @@ -37,9 +37,7 @@ import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; -import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; -import org.apache.rocketmq.remoting.RPCHook; public abstract class TopicRouteService extends AbstractStartAndShutdown { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -50,7 +48,7 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown { private final ScheduledExecutorService scheduledExecutorService; private final ThreadPoolExecutor cacheRefreshExecutor; - public TopicRouteService(RPCHook rpcHook) { + public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) { ProxyConfig config = ConfigurationManager.getProxyConfig(); this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( @@ -64,13 +62,7 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown { "TopicRouteCacheRefresh", config.getTopicRouteServiceThreadPoolQueueCapacity() ); - this.mqClientAPIFactory = new MQClientAPIFactory( - "TopicRouteServiceClient_", - 1, - new DoNothingClientRemotingProcessor(null), - rpcHook, - this.scheduledExecutorService - ); + this.mqClientAPIFactory = mqClientAPIFactory; this.topicCache = CacheBuilder.newBuilder() .maximumSize(config.getTopicRouteServiceCacheMaxNum()) .refreshAfterWrite(config.getTopicRouteServiceCacheExpiredInSeconds(), TimeUnit.SECONDS) From 9fe1bbc4dfad6c13add71c85948481b4e14af3bb Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 17 May 2022 21:00:06 +0800 Subject: [PATCH 185/338] [ISSUE #3949] Fix configuration --- .../rocketmq/proxy/config/ProxyConfig.java | 38 +++++-------------- .../metadata/AbstractMetadataService.java | 6 +-- .../metadata/ClusterMetadataService.java | 4 +- .../metadata/LocalMetadataService.java | 4 +- 4 files changed, 17 insertions(+), 35 deletions(-) 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 ead79f5228..1c531d92d9 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 @@ -80,11 +80,9 @@ public class ProxyConfig { private int topicRouteServiceThreadPoolQueueCapacity = 5000; private int topicConfigCacheExpiredInSeconds = 20; - private int topicConfigCacheExecutorThreadNum = 3; - private int topicConfigCacheExecutorQueueCapacity = 1000; private int topicConfigCacheMaxNum = 20000; - private int topicConfigThreadPoolNums = 36; - private int topicConfigThreadPoolQueueCapacity = 50000; + private int metadataThreadPoolNums = 3; + private int metadataThreadPoolQueueCapacity = 1000; private int transactionHeartbeatThreadPoolNums = 20; private int transactionHeartbeatThreadPoolQueueCapacity = 200; @@ -417,22 +415,6 @@ public class ProxyConfig { this.topicConfigCacheExpiredInSeconds = topicConfigCacheExpiredInSeconds; } - public int getTopicConfigCacheExecutorThreadNum() { - return topicConfigCacheExecutorThreadNum; - } - - public void setTopicConfigCacheExecutorThreadNum(int topicConfigCacheExecutorThreadNum) { - this.topicConfigCacheExecutorThreadNum = topicConfigCacheExecutorThreadNum; - } - - public int getTopicConfigCacheExecutorQueueCapacity() { - return topicConfigCacheExecutorQueueCapacity; - } - - public void setTopicConfigCacheExecutorQueueCapacity(int topicConfigCacheExecutorQueueCapacity) { - this.topicConfigCacheExecutorQueueCapacity = topicConfigCacheExecutorQueueCapacity; - } - public int getTopicConfigCacheMaxNum() { return topicConfigCacheMaxNum; } @@ -441,20 +423,20 @@ public class ProxyConfig { this.topicConfigCacheMaxNum = topicConfigCacheMaxNum; } - public int getTopicConfigThreadPoolNums() { - return topicConfigThreadPoolNums; + public int getMetadataThreadPoolNums() { + return metadataThreadPoolNums; } - public void setTopicConfigThreadPoolNums(int topicConfigThreadPoolNums) { - this.topicConfigThreadPoolNums = topicConfigThreadPoolNums; + public void setMetadataThreadPoolNums(int metadataThreadPoolNums) { + this.metadataThreadPoolNums = metadataThreadPoolNums; } - public int getTopicConfigThreadPoolQueueCapacity() { - return topicConfigThreadPoolQueueCapacity; + public int getMetadataThreadPoolQueueCapacity() { + return metadataThreadPoolQueueCapacity; } - public void setTopicConfigThreadPoolQueueCapacity(int topicConfigThreadPoolQueueCapacity) { - this.topicConfigThreadPoolQueueCapacity = topicConfigThreadPoolQueueCapacity; + public void setMetadataThreadPoolQueueCapacity(int metadataThreadPoolQueueCapacity) { + this.metadataThreadPoolQueueCapacity = metadataThreadPoolQueueCapacity; } public int getTransactionHeartbeatThreadPoolNums() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java index e6ca6bdfc1..03742f200e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java @@ -37,12 +37,12 @@ public abstract class AbstractMetadataService extends AbstractStartAndShutdown i public AbstractMetadataService() { ProxyConfig config = ConfigurationManager.getProxyConfig(); this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( - config.getTopicConfigThreadPoolNums(), - config.getTopicConfigThreadPoolNums(), + config.getMetadataThreadPoolNums(), + config.getMetadataThreadPoolNums(), 1000 * 60, TimeUnit.MILLISECONDS, "MetadataCacheRefresh", - config.getTopicConfigThreadPoolQueueCapacity() + config.getMetadataThreadPoolQueueCapacity() ); } 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 52acefe127..edf011608d 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 @@ -40,8 +40,8 @@ public class ClusterMetadataService extends AbstractMetadataService { this.topicRouteService = topicRouteService; ProxyConfig config = ConfigurationManager.getProxyConfig(); this.topicCache = CacheBuilder.newBuilder() - .maximumSize(config.getTopicRouteCacheMaxNum()) - .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) + .maximumSize(config.getTopicConfigCacheMaxNum()) + .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new ClusterTopicConfigCacheLoader(mqClientAPIFactory)); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java index 7bf0ece856..0c2689268d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java @@ -34,8 +34,8 @@ public class LocalMetadataService extends AbstractMetadataService { ProxyConfig config = ConfigurationManager.getProxyConfig(); this.topicCache = CacheBuilder.newBuilder() - .maximumSize(config.getTopicRouteCacheMaxNum()) - .refreshAfterWrite(config.getTopicRouteCacheExpiredInSeconds(), TimeUnit.SECONDS) + .maximumSize(config.getTopicConfigCacheMaxNum()) + .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new LocalTopicConfigCacheLoader(brokerController)); } From 20e9bdd3e4abdc69a8cdef85596da520aa1e435c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 17 May 2022 21:06:00 +0800 Subject: [PATCH 186/338] [ISSUE #3949] v2 support --- .../rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java | 8 ++++---- .../proxy/grpc/v2/consumer/ReceiveMessageActivity.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 85c0059c13..52cea43719 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -83,7 +83,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ config.getGrpcProducerThreadPoolNums(), 1, TimeUnit.MINUTES, - "GrpcRouteThreadPool", + "GrpcProducerThreadPool", config.getGrpcProducerThreadQueueCapacity() ); this.consumerThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( @@ -91,7 +91,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ config.getGrpcConsumerThreadPoolNums(), 1, TimeUnit.MINUTES, - "GrpcRouteThreadPool", + "GrpcConsumerThreadPool", config.getGrpcConsumerThreadQueueCapacity() ); this.clientManagerThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( @@ -99,7 +99,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ config.getGrpcClientManagerThreadPoolNums(), 1, TimeUnit.MINUTES, - "GrpcRouteThreadPool", + "GrpcClientManagerThreadPool", config.getGrpcClientManagerThreadQueueCapacity() ); this.transactionThreadPoolExecutor = ThreadPoolMonitor.createAndMonitor( @@ -107,7 +107,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ config.getGrpcTransactionThreadPoolNums(), 1, TimeUnit.MINUTES, - "GrpcRouteThreadPool", + "GrpcTransactionThreadPool", config.getGrpcTransactionThreadQueueCapacity() ); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 27dc411ba9..673abca54d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -63,7 +63,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { pollTime = timeRemaining; } if (pollTime <= 0) { - writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "no new message"); + writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); return; } From 95b8105ffac6587edd36c0c9184658c70b000cb4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 18 May 2022 17:34:15 +0800 Subject: [PATCH 187/338] [ISSUE #3949] support config retryPolicy and consumeMessageOrderly in subscriptionGroupConfig --- .../proxy/common/utils/ProxyUtils.java | 1 + .../rocketmq/proxy/config/ProxyConfig.java | 37 ++++-- .../grpc/v2/DefaultGrpcMessingActivity.java | 4 +- .../proxy/grpc/v2/client/ClientActivity.java | 6 +- .../v2/common/GrpcClientSettingsManager.java | 93 +++++++++++-- .../consumer/PopMessageResultFilterImpl.java | 3 +- .../v2/consumer/ReceiveMessageActivity.java | 107 +++++++-------- .../processor/DefaultMessagingProcessor.java | 6 + .../proxy/processor/MessagingProcessor.java | 6 + .../metadata/AbstractMetadataService.java | 69 ---------- .../metadata/ClusterMetadataService.java | 122 ++++++++++++++---- .../metadata/LocalMetadataService.java | 43 ++---- .../service/metadata/MetadataService.java | 4 + .../proxy/grpc/v2/BaseActivityTest.java | 4 +- .../consumer/ReceiveMessageActivityTest.java | 5 + 15 files changed, 305 insertions(+), 205 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index 6b9ea2cf7e..61eb131ee2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -17,5 +17,6 @@ package org.apache.rocketmq.proxy.common.utils; public class ProxyUtils { + public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; } 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 1c531d92d9..6d56457a14 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 @@ -23,6 +23,8 @@ public class ProxyConfig { public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; private static final int PROCESSOR_NUMBER = Runtime.getRuntime().availableProcessors(); + private String rocketMQClusterName = ""; + /** * configuration for ThreadPoolMonitor */ @@ -36,7 +38,6 @@ public class ProxyConfig { * gRPC */ private String proxyMode = ProxyMode.CLUSTER.name(); - private Boolean startGrpcServer = true; private Integer grpcServerPort = 8081; private boolean grpcTlsTestModeEnable = true; private String grpcTlsKeyPath = ConfigurationManager.getProxyHome() + "/conf/tls/rocketmq.key"; @@ -81,6 +82,8 @@ public class ProxyConfig { private int topicConfigCacheExpiredInSeconds = 20; private int topicConfigCacheMaxNum = 20000; + private int subscriptionGroupConfigCacheExpiredInSeconds = 20; + private int subscriptionGroupConfigCacheMaxNum = 20000; private int metadataThreadPoolNums = 3; private int metadataThreadPoolQueueCapacity = 1000; @@ -95,6 +98,14 @@ public class ProxyConfig { private boolean enableTopicMessageTypeCheck = true; + public String getRocketMQClusterName() { + return rocketMQClusterName; + } + + public void setRocketMQClusterName(String rocketMQClusterName) { + this.rocketMQClusterName = rocketMQClusterName; + } + public boolean isEnablePrintJstack() { return enablePrintJstack; } @@ -143,14 +154,6 @@ public class ProxyConfig { this.proxyMode = proxyMode; } - public Boolean getStartGrpcServer() { - return startGrpcServer; - } - - public void setStartGrpcServer(Boolean startGrpcServer) { - this.startGrpcServer = startGrpcServer; - } - public Integer getGrpcServerPort() { return grpcServerPort; } @@ -423,6 +426,22 @@ public class ProxyConfig { this.topicConfigCacheMaxNum = topicConfigCacheMaxNum; } + public int getSubscriptionGroupConfigCacheExpiredInSeconds() { + return subscriptionGroupConfigCacheExpiredInSeconds; + } + + public void setSubscriptionGroupConfigCacheExpiredInSeconds(int subscriptionGroupConfigCacheExpiredInSeconds) { + this.subscriptionGroupConfigCacheExpiredInSeconds = subscriptionGroupConfigCacheExpiredInSeconds; + } + + public int getSubscriptionGroupConfigCacheMaxNum() { + return subscriptionGroupConfigCacheMaxNum; + } + + public void setSubscriptionGroupConfigCacheMaxNum(int subscriptionGroupConfigCacheMaxNum) { + this.subscriptionGroupConfigCacheMaxNum = subscriptionGroupConfigCacheMaxNum; + } + public int getMetadataThreadPoolNums() { return metadataThreadPoolNums; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index f63ee61816..50d5f180a0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -58,7 +58,7 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private GrpcClientSettingsManager grpcClientSettingsManager; + private final GrpcClientSettingsManager grpcClientSettingsManager; private final ReceiveMessageActivity receiveMessageActivity; private final AckMessageActivity ackMessageActivity; @@ -70,7 +70,7 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme private final ClientActivity clientActivity; protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { - this.grpcClientSettingsManager = new GrpcClientSettingsManager(); + this.grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, this.grpcClientSettingsManager); this.ackMessageActivity = new AckMessageActivity(messagingProcessor, this.grpcClientSettingsManager); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 854507370b..5cbcc94244 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -95,7 +95,7 @@ public class ClientActivity extends AbstractMessingActivity { String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); - Settings clientSettings = grpcClientSettingsManager.getClientSettings(clientId); + Settings clientSettings = grpcClientSettingsManager.getClientSettings(context); switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { @@ -150,7 +150,7 @@ public class ClientActivity extends AbstractMessingActivity { ProxyContext context = createContext(ctx); String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); - Settings clientSettings = grpcClientSettingsManager.getClientSettings(clientId); + Settings clientSettings = grpcClientSettingsManager.getClientSettings(context); switch (clientSettings.getClientType()) { case PRODUCER: @@ -225,7 +225,7 @@ public class ClientActivity extends AbstractMessingActivity { ProxyContext context = createContext(ctx); String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); - Settings settings = grpcClientSettingsManager.getClientSettings(clientId); + Settings settings = grpcClientSettingsManager.getClientSettings(context); if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index b5f8bde099..834a4d37b9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -17,15 +17,28 @@ package org.apache.rocketmq.proxy.grpc.v2.common; +import apache.rocketmq.v2.CustomizedBackoff; import apache.rocketmq.v2.ExponentialBackoff; import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; +import com.google.protobuf.Duration; import com.google.protobuf.util.Durations; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.apache.rocketmq.common.subscription.CustomizedRetryPolicy; +import org.apache.rocketmq.common.subscription.ExponentialRetryPolicy; +import org.apache.rocketmq.common.subscription.GroupRetryPolicy; +import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class GrpcClientSettingsManager { @@ -44,25 +57,79 @@ public class GrpcClientSettingsManager { .setMaxBodySize(4 * 1024 * 1024) .build()) .build(); - protected static final Settings DEFAULT_CONSUMER_SETTINGS = Settings.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(3) - .setExponentialBackoff(ExponentialBackoff.newBuilder() - .setInitial(Durations.fromSeconds(1)) - .setMax(Durations.fromSeconds(3)) - .setMultiplier(2) - .build()) - .build()) + protected static final Settings DEFAULT_CONSUMER_SETTINGS = mergeSubscriptionData(Settings.newBuilder() .setSubscription(Subscription.newBuilder() - .setFifo(false) .setReceiveBatchSize(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) .setLongPollingTimeout(Durations.fromSeconds(30)) .build()) - .build(); + .build(), new SubscriptionGroupConfig()); + protected static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); - public Settings getClientSettings(String clientId) { - return CLIENT_SETTINGS_MAP.get(clientId); + private final MessagingProcessor messagingProcessor; + + public GrpcClientSettingsManager(MessagingProcessor messagingProcessor) { + this.messagingProcessor = messagingProcessor; + } + + public Settings getClientSettings(ProxyContext ctx) { + String clientId = ctx.getVal(GrpcContextConstants.CLIENT_ID); + Settings settings = CLIENT_SETTINGS_MAP.get(clientId); + if (settings.hasSubscription()) { + settings = mergeSubscriptionData(ctx, settings, + GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup())); + } + return settings; + } + + private Settings mergeSubscriptionData(ProxyContext ctx, Settings settings, String consumerGroup) { + SubscriptionGroupConfig config = this.messagingProcessor.getSubscriptionGroupConfig(ctx, consumerGroup); + if (config == null) { + return settings; + } + + return mergeSubscriptionData(settings, config); + } + + protected static Settings mergeSubscriptionData(Settings settings, SubscriptionGroupConfig config) { + Settings.Builder resultSettingsBuilder = settings.toBuilder(); + + resultSettingsBuilder.getSubscriptionBuilder().setFifo(config.isConsumeMessageOrderly()); + + resultSettingsBuilder.getBackoffPolicyBuilder().setMaxAttempts(config.getRetryMaxTimes()); + + GroupRetryPolicy groupRetryPolicy = config.getGroupRetryPolicy(); + if (groupRetryPolicy.getType().equals(GroupRetryPolicyType.EXPONENTIAL)) { + ExponentialRetryPolicy exponentialRetryPolicy = groupRetryPolicy.getExponentialRetryPolicy(); + if (exponentialRetryPolicy == null) { + exponentialRetryPolicy = new ExponentialRetryPolicy(); + } + resultSettingsBuilder.getBackoffPolicyBuilder().setExponentialBackoff(convertToExponentialBackoff(exponentialRetryPolicy)); + } else { + CustomizedRetryPolicy customizedRetryPolicy = groupRetryPolicy.getCustomizedRetryPolicy(); + if (customizedRetryPolicy == null) { + customizedRetryPolicy = new CustomizedRetryPolicy(); + } + resultSettingsBuilder.getBackoffPolicyBuilder().setCustomizedBackoff(convertToCustomizedRetryPolicy(customizedRetryPolicy)); + } + + return resultSettingsBuilder.build(); + } + + protected static ExponentialBackoff convertToExponentialBackoff(ExponentialRetryPolicy retryPolicy) { + return ExponentialBackoff.newBuilder() + .setInitial(Durations.fromMillis(retryPolicy.getInitial())) + .setMax(Durations.fromMillis(retryPolicy.getMax())) + .setMultiplier(retryPolicy.getMultiplier()) + .build(); + } + + protected static CustomizedBackoff convertToCustomizedRetryPolicy(CustomizedRetryPolicy retryPolicy) { + List durationList = Arrays.stream(retryPolicy.getNext()) + .mapToObj(Durations::fromMillis).collect(Collectors.toList()); + return CustomizedBackoff.newBuilder() + .addAllNext(durationList) + .build(); } public void updateClientSettings(String clientId, Settings settings) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java index 23842c6fab..d411184149 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java @@ -21,7 +21,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.utils.FilterUtils; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; -import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; import org.apache.rocketmq.proxy.processor.PopMessageResultFilter; public class PopMessageResultFilterImpl implements PopMessageResultFilter { @@ -34,7 +33,7 @@ public class PopMessageResultFilterImpl implements PopMessageResultFilter { @Override public FilterResult filterMessage(ProxyContext ctx, String consumerGroup, SubscriptionData subscriptionData, MessageExt messageExt) { - int maxAttempts = grpcClientSettingsManager.getClientSettings(ctx.getVal(GrpcContextConstants.CLIENT_ID)).getBackoffPolicy().getMaxAttempts(); + int maxAttempts = grpcClientSettingsManager.getClientSettings(ctx).getBackoffPolicy().getMaxAttempts(); if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { return FilterResult.NO_MATCH; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 673abca54d..f3965037a8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -20,6 +20,8 @@ import apache.rocketmq.v2.Code; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.stub.StreamObserver; @@ -31,7 +33,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; 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.GrpcContextConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; @@ -50,63 +51,67 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { ProxyContext proxyContext = createContext(ctx); - boolean fifo = false; - ReceiveMessageResponseStreamWriter writer = new ReceiveMessageResponseStreamWriter( this.messagingProcessor, responseObserver ); - long timeRemaining = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } - if (pollTime <= 0) { - writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); - return; - } - - long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); - if (request.getAutoRenew()) { - invisibleTime = Durations.toMillis( - this.grpcClientSettingsManager.getClientSettings(proxyContext.getVal(GrpcContextConstants.CLIENT_ID)) - .getSubscription().getLongPollingTimeout() - ); - } - - String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - FilterExpression filterExpression = request.getFilterExpression(); - SubscriptionData subscriptionData; try { - subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), - GrpcConverter.buildExpressionType(filterExpression.getType())); - } catch (Exception e) { - writer.write(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); - return; - } + Settings settings = this.grpcClientSettingsManager.getClientSettings(proxyContext); + Subscription subscription = settings.getSubscription(); + boolean fifo = subscription.getFifo(); - this.messagingProcessor.popMessage( - proxyContext, - new ReceiveMessageQueueSelector( - request.getMessageQueue().getBroker().getName() - ), - group, - topic, - request.getBatchSize(), - invisibleTime, - pollTime, - ConsumeInitMode.MAX, - subscriptionData, - fifo, - new PopMessageResultFilterImpl(grpcClientSettingsManager), - timeRemaining - ).thenAccept(popResult -> writer.write(proxyContext, request, popResult)) - .exceptionally(t -> { - writer.write(proxyContext, request, t); - return null; - }); + long timeRemaining = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); + long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + if (pollTime <= 0) { + pollTime = timeRemaining; + } + if (pollTime <= 0) { + writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); + return; + } + + long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); + if (request.getAutoRenew()) { + invisibleTime = Durations.toMillis(subscription.getLongPollingTimeout() + ); + } + + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + FilterExpression filterExpression = request.getFilterExpression(); + SubscriptionData subscriptionData; + try { + subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), + GrpcConverter.buildExpressionType(filterExpression.getType())); + } catch (Exception e) { + writer.write(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); + return; + } + + this.messagingProcessor.popMessage( + proxyContext, + new ReceiveMessageQueueSelector( + request.getMessageQueue().getBroker().getName() + ), + group, + topic, + request.getBatchSize(), + invisibleTime, + pollTime, + ConsumeInitMode.MAX, + subscriptionData, + fifo, + new PopMessageResultFilterImpl(grpcClientSettingsManager), + timeRemaining + ).thenAccept(popResult -> writer.write(proxyContext, request, popResult)) + .exceptionally(t -> { + writer.write(proxyContext, request, t); + return null; + }); + } catch (Throwable t) { + writer.write(proxyContext, request, t); + } } protected static class ReceiveMessageQueueSelector implements QueueSelector { 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 0269b752be..c159dec05d 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 @@ -36,6 +36,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.Address; @@ -112,6 +113,11 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen this.appendShutdown(this.consumerProcessorExecutor::shutdown); } + @Override + public SubscriptionGroupConfig getSubscriptionGroupConfig(ProxyContext ctx, String consumerGroupName) { + return this.serviceManager.getMetadataService().getSubscriptionGroupConfig(consumerGroupName); + } + @Override public ProxyTopicRouteData getTopicRouteDataForProxy(ProxyContext ctx, List
requestHostAndPortList, String topicName) throws Exception { 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 10ac52c1c0..eee9f98731 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 @@ -34,6 +34,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -47,6 +48,11 @@ public interface MessagingProcessor extends StartAndShutdown { long DEFAULT_TIMEOUT_MILLS = Duration.ofSeconds(2).toMillis(); + SubscriptionGroupConfig getSubscriptionGroupConfig( + ProxyContext ctx, + String consumerGroupName + ); + ProxyTopicRouteData getTopicRouteDataForProxy( ProxyContext ctx, List
requestHostAndPortList, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java deleted file mode 100644 index 03742f200e..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/AbstractMetadataService.java +++ /dev/null @@ -1,69 +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.proxy.service.metadata; - -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.common.attribute.TopicMessageType; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; -import org.apache.rocketmq.common.thread.ThreadPoolMonitor; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.AbstractCacheLoader; -import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.ProxyConfig; - -public abstract class AbstractMetadataService extends AbstractStartAndShutdown implements MetadataService { - protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - protected final ThreadPoolExecutor cacheRefreshExecutor; - - public AbstractMetadataService() { - ProxyConfig config = ConfigurationManager.getProxyConfig(); - this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( - config.getMetadataThreadPoolNums(), - config.getMetadataThreadPoolNums(), - 1000 * 60, - TimeUnit.MILLISECONDS, - "MetadataCacheRefresh", - config.getMetadataThreadPoolQueueCapacity() - ); - } - - public abstract TopicMessageType getTopicMessageType(String topic); - - protected abstract class AbstractTopicConfigCacheLoader extends AbstractCacheLoader { - - public AbstractTopicConfigCacheLoader() { - super(cacheRefreshExecutor); - } - - protected abstract TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception; - - @Override - public TopicConfigAndQueueMapping getDirectly(String topic) throws Exception { - return loadTopicConfig(topic); - } - - @Override - protected void onErr(String key, Exception e) { - log.error("load topic config failed. topic:{}", key, e); - } - } -} 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 edf011608d..3be7b051b9 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 @@ -20,32 +20,64 @@ package org.apache.rocketmq.proxy.service.metadata; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; import java.util.Optional; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.AbstractCacheLoader; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; import org.apache.rocketmq.proxy.service.route.TopicRouteService; -public class ClusterMetadataService extends AbstractMetadataService { +public class ClusterMetadataService extends AbstractStartAndShutdown implements MetadataService { + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private static final long DEFAULT_TIMEOUT = 3000; + + private final ThreadPoolExecutor cacheRefreshExecutor; + private final TopicRouteService topicRouteService; + private final MQClientAPIFactory mqClientAPIFactory; + private final LoadingCache topicCache; - private TopicRouteService topicRouteService; private final static TopicConfigAndQueueMapping EMPTY_TOPIC_CONFIG = new TopicConfigAndQueueMapping(); + private final LoadingCache subscriptionGroupConfigCache; + private final static SubscriptionGroupConfig EMPTY_SUBSCRIPTION_GROUP_CONFIG = new SubscriptionGroupConfig(); + public ClusterMetadataService(TopicRouteService topicRouteService, MQClientAPIFactory mqClientAPIFactory) { this.topicRouteService = topicRouteService; + this.mqClientAPIFactory = mqClientAPIFactory; + ProxyConfig config = ConfigurationManager.getProxyConfig(); + this.cacheRefreshExecutor = ThreadPoolMonitor.createAndMonitor( + config.getMetadataThreadPoolNums(), + config.getMetadataThreadPoolNums(), + 1000 * 60, + TimeUnit.MILLISECONDS, + "MetadataCacheRefresh", + config.getMetadataThreadPoolQueueCapacity() + ); this.topicCache = CacheBuilder.newBuilder() .maximumSize(config.getTopicConfigCacheMaxNum()) .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) - .build(new ClusterTopicConfigCacheLoader(mqClientAPIFactory)); + .build(new ClusterTopicConfigCacheLoader()); + this.subscriptionGroupConfigCache = CacheBuilder.newBuilder() + .maximumSize(config.getSubscriptionGroupConfigCacheMaxNum()) + .refreshAfterWrite(config.getSubscriptionGroupConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) + .build(new ClusterSubscriptionGroupConfigCacheLoader()); } - @Override public TopicMessageType getTopicMessageType(String topic) { + @Override + public TopicMessageType getTopicMessageType(String topic) { TopicConfigAndQueueMapping topicConfigAndQueueMapping; try { topicConfigAndQueueMapping = topicCache.get(topic); @@ -58,28 +90,74 @@ public class ClusterMetadataService extends AbstractMetadataService { return topicConfigAndQueueMapping.getTopicMessageType(); } - protected class ClusterTopicConfigCacheLoader extends AbstractTopicConfigCacheLoader { - private final MQClientAPIFactory mqClientAPIFactory; + @Override + public SubscriptionGroupConfig getSubscriptionGroupConfig(String group) { + SubscriptionGroupConfig config; + try { + config = this.subscriptionGroupConfigCache.get(group); + } catch (Exception e) { + return null; + } + if (config == EMPTY_SUBSCRIPTION_GROUP_CONFIG) { + return null; + } + return config; + } - public ClusterTopicConfigCacheLoader(MQClientAPIFactory mqClientAPIFactory) { - this.mqClientAPIFactory = mqClientAPIFactory; + protected class ClusterSubscriptionGroupConfigCacheLoader extends AbstractCacheLoader { + + public ClusterSubscriptionGroupConfigCacheLoader() { + super(cacheRefreshExecutor); } - @Override protected TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception { - try { - Optional brokerDataOptional = topicRouteService.getAllMessageQueueView(topic).getTopicRouteData().getBrokerDatas().stream().findAny(); - if (brokerDataOptional.isPresent()) { - String brokerAddress = topicRouteService.getBrokerAddr(brokerDataOptional.get().getBrokerName()); - return this.mqClientAPIFactory.getClient().getTopicConfig(brokerAddress, topic, 1000L); - } - return EMPTY_TOPIC_CONFIG; - } catch (MQClientException e) { - if (TopicRouteHelper.isTopicNotExistError(e)) { - log.warn("topic is not exist", e); - return EMPTY_TOPIC_CONFIG; - } - throw e; + @Override + protected SubscriptionGroupConfig getDirectly(String consumerGroup) throws Exception { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + String clusterName = config.getRocketMQClusterName(); + Optional brokerDataOptional = findOneBroker(clusterName); + if (brokerDataOptional.isPresent()) { + String brokerAddress = brokerDataOptional.get().selectBrokerAddr(); + return mqClientAPIFactory.getClient().getSubscriptionGroupConfig(brokerAddress, consumerGroup, DEFAULT_TIMEOUT); } + return EMPTY_SUBSCRIPTION_GROUP_CONFIG; + } + + @Override + protected void onErr(String consumerGroup, Exception e) { + log.error("load subscription config failed. consumerGroup:{}", consumerGroup, e); + } + } + + protected class ClusterTopicConfigCacheLoader extends AbstractCacheLoader { + + public ClusterTopicConfigCacheLoader() { + super(cacheRefreshExecutor); + } + + @Override + protected TopicConfigAndQueueMapping getDirectly(String topic) throws Exception { + Optional brokerDataOptional = findOneBroker(topic); + if (brokerDataOptional.isPresent()) { + String brokerAddress = brokerDataOptional.get().selectBrokerAddr(); + return mqClientAPIFactory.getClient().getTopicConfig(brokerAddress, topic, DEFAULT_TIMEOUT); + } + return EMPTY_TOPIC_CONFIG; + } + + @Override + protected void onErr(String key, Exception e) { + log.error("load topic config failed. topic:{}", key, e); + } + } + + protected Optional findOneBroker(String topic) throws Exception { + try { + return topicRouteService.getAllMessageQueueView(topic).getTopicRouteData().getBrokerDatas().stream().findAny(); + } catch (MQClientException e) { + if (TopicRouteHelper.isTopicNotExistError(e)) { + return Optional.empty(); + } + throw e; } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java index 0c2689268d..6f06f84888 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/LocalMetadataService.java @@ -17,52 +17,29 @@ package org.apache.rocketmq.proxy.service.metadata; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.LoadingCache; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.attribute.TopicMessageType; -import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; -public class LocalMetadataService extends AbstractMetadataService { - private final LoadingCache topicCache; +public class LocalMetadataService implements MetadataService { + private final BrokerController brokerController; public LocalMetadataService(BrokerController brokerController) { - ProxyConfig config = ConfigurationManager.getProxyConfig(); - - this.topicCache = CacheBuilder.newBuilder() - .maximumSize(config.getTopicConfigCacheMaxNum()) - .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) - .build(new LocalTopicConfigCacheLoader(brokerController)); + this.brokerController = brokerController; } @Override public TopicMessageType getTopicMessageType(String topic) { - try { - TopicConfigAndQueueMapping topicConfigAndQueueMapping = topicCache.get(topic); - if (topicConfigAndQueueMapping == null) { - return TopicMessageType.UNSPECIFIED; - } - return topicConfigAndQueueMapping.getTopicMessageType(); - } catch (Exception e) { - log.error("getTopicMessageType error", topic, e); + TopicConfig topicConfig = brokerController.getTopicConfigManager().selectTopicConfig(topic); + if (topicConfig == null) { return TopicMessageType.UNSPECIFIED; } + return topicConfig.getTopicMessageType(); } - protected class LocalTopicConfigCacheLoader extends AbstractTopicConfigCacheLoader { - private final BrokerController brokerController; - - public LocalTopicConfigCacheLoader(BrokerController brokerController) { - this.brokerController = brokerController; - } - - @Override protected TopicConfigAndQueueMapping loadTopicConfig(String topic) throws Exception { - TopicConfig topicConfig = brokerController.getTopicConfigManager().selectTopicConfig(topic); - return new TopicConfigAndQueueMapping(topicConfig, null); - } + @Override + public SubscriptionGroupConfig getSubscriptionGroupConfig(String group) { + return this.brokerController.getSubscriptionGroupManager().getSubscriptionGroupTable().get(group); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java index a87ec1484f..6951845e52 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/metadata/MetadataService.java @@ -18,7 +18,11 @@ package org.apache.rocketmq.proxy.service.metadata; import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; public interface MetadataService { + TopicMessageType getTopicMessageType(String topic); + + SubscriptionGroupConfig getSubscriptionGroupConfig(String group); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index c155b382e8..751c62f7c0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -51,9 +51,11 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { protected static final String LOCAL_ADDR = "127.0.0.1:8080"; protected Metadata metadata = new Metadata(); + protected static final String CLIENT_ID = "client-id" + UUID.randomUUID(); + public void before() throws Throwable { super.before(); - metadata.put(InterceptorConstants.CLIENT_ID, "client-id" + UUID.randomUUID()); + metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); 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 86cb54dd59..ae5bef6eec 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 @@ -24,6 +24,7 @@ import apache.rocketmq.v2.MessageQueue; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import java.util.ArrayList; @@ -63,6 +64,8 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + when(this.grpcClientSettingsManager.getClientSettings(any())).thenReturn(Settings.newBuilder().getDefaultInstanceForType()); + this.receiveMessageActivity.receiveMessage( createContext(), ReceiveMessageRequest.newBuilder() @@ -85,6 +88,8 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + when(this.grpcClientSettingsManager.getClientSettings(any())).thenReturn(Settings.newBuilder().getDefaultInstanceForType()); + PopResult popResult = new PopResult(PopStatus.NO_NEW_MSG, new ArrayList<>()); when(this.messagingProcessor.popMessage( any(), From bb5e55df163d34c8e19d6f08910a7d055f86e559 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 18 May 2022 17:36:58 +0800 Subject: [PATCH 188/338] [ISSUE #3949] add shutdown in ClusterMetadataService --- .../rocketmq/proxy/service/ClusterServiceManager.java | 3 ++- .../proxy/service/metadata/ClusterMetadataService.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) 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 74b0052b03..91604cb13b 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 @@ -55,7 +55,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S private final TopicRouteService topicRouteService; private final MessageService messageService; private final ProxyRelayService proxyRelayService; - private final MetadataService metadataService; + private final ClusterMetadataService metadataService; private final ScheduledExecutorService scheduledExecutorService; private final MQClientAPIFactory messagingClientAPIFactory; @@ -107,6 +107,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S this.appendStartAndShutdown(this.operationClientAPIFactory); this.appendStartAndShutdown(this.topicRouteService); this.appendStartAndShutdown(this.clusterTransactionService); + this.appendStartAndShutdown(this.metadataService); } @Override 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 3be7b051b9..a5b18636d6 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 @@ -74,6 +74,12 @@ public class ClusterMetadataService extends AbstractStartAndShutdown implements .maximumSize(config.getSubscriptionGroupConfigCacheMaxNum()) .refreshAfterWrite(config.getSubscriptionGroupConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new ClusterSubscriptionGroupConfigCacheLoader()); + + this.init(); + } + + protected void init() { + this.appendShutdown(this.cacheRefreshExecutor::shutdown); } @Override From 610ab04ec7e3a867f141a195da3f8589b30a1700 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 18 May 2022 21:01:31 +0800 Subject: [PATCH 189/338] [ISSUE #3949] add test cases --- .../grpc/v2/producer/SendMessageActivity.java | 42 ++-- .../v2/producer/SendMessageActivityTest.java | 223 ++++++++++++++++++ 2 files changed, 250 insertions(+), 15 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java 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 49edbcaba8..249630a224 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 @@ -39,7 +39,6 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; @@ -192,21 +191,34 @@ public class SendMessageActivity extends AbstractMessingActivity { protected SendMessageResponse convertToSendMessageResponse(ProxyContext ctx, SendMessageRequest request, SendResult result) { - if (result.getSendStatus() != SendStatus.SEND_OK) { - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); + switch (result.getSendStatus()) { + case FLUSH_DISK_TIMEOUT: + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.MASTER_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + case FLUSH_SLAVE_TIMEOUT: + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.SLAVE_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + case SLAVE_NOT_AVAILABLE: + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.HA_NOT_AVAILABLE, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + case SEND_OK: + List sendReceiptList = Lists.newArrayList(); + sendReceiptList.add(SendReceipt.newBuilder() + .setMessageId(StringUtils.defaultString(result.getMsgId())) + .setTransactionId(StringUtils.defaultString(result.getTransactionId())) + .build()); + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addAllReceipts(sendReceiptList) + .build(); + default: + return SendMessageResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); } - - List sendReceiptList = Lists.newArrayList(); - sendReceiptList.add(SendReceipt.newBuilder() - .setMessageId(StringUtils.defaultString(result.getMsgId())) - .setTransactionId(StringUtils.defaultString(result.getTransactionId())) - .build()); - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllReceipts(sendReceiptList) - .build(); } protected static class SendMessageQueueSelector implements QueueSelector { 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 new file mode 100644 index 0000000000..682cf32b6b --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/SendMessageActivityTest.java @@ -0,0 +1,223 @@ +/* + * 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.grpc.v2.producer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Encoding; +import apache.rocketmq.v2.Message; +import apache.rocketmq.v2.MessageType; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.SendMessageResponse; +import apache.rocketmq.v2.SystemProperties; +import com.google.protobuf.ByteString; +import com.google.protobuf.util.Durations; +import com.google.protobuf.util.Timestamps; +import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +public class SendMessageActivityTest extends BaseActivityTest { + + private static final String TOPIC = "topic"; + private static final String CONSUMER_GROUP = "consumerGroup"; + + private SendMessageActivity sendMessageActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.sendMessageActivity = new SendMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void sendMessage() throws Exception { + String msgId = MessageClientIDSetter.createUniqID(); + + SendResult sendResult = new SendResult(); + sendResult.setSendStatus(SendStatus.SEND_OK); + sendResult.setMsgId(msgId); + when(this.messagingProcessor.sendMessage(any(), any(), anyString(), any())) + .thenReturn(CompletableFuture.completedFuture(sendResult)); + + SendMessageResponse response = this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(msgId) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(msgId, response.getReceipts(0).getMessageId()); + } + + @Test + public void testConvertToSendMessageResponse() { + assertEquals( + Code.MASTER_PERSISTENCE_TIMEOUT, + this.sendMessageActivity.convertToSendMessageResponse( + ProxyContext.create(), + SendMessageRequest.newBuilder().build(), + new SendResult(SendStatus.FLUSH_DISK_TIMEOUT, null, null, null, 0) + ).getStatus().getCode() + ); + assertEquals( + Code.SLAVE_PERSISTENCE_TIMEOUT, + this.sendMessageActivity.convertToSendMessageResponse( + ProxyContext.create(), + SendMessageRequest.newBuilder().build(), + new SendResult(SendStatus.FLUSH_SLAVE_TIMEOUT, null, null, null, 0) + ).getStatus().getCode() + ); + assertEquals( + Code.HA_NOT_AVAILABLE, + this.sendMessageActivity.convertToSendMessageResponse( + ProxyContext.create(), + SendMessageRequest.newBuilder().build(), + new SendResult(SendStatus.SLAVE_NOT_AVAILABLE, null, null, null, 0) + ).getStatus().getCode() + ); + assertEquals( + Code.OK, + this.sendMessageActivity.convertToSendMessageResponse( + ProxyContext.create(), + SendMessageRequest.newBuilder().build(), + new SendResult(SendStatus.SEND_OK, null, null, null, 0) + ).getStatus().getCode() + ); + } + + @Test(expected = GrpcProxyException.class) + public void testBuildErrorMessage() { + this.sendMessageActivity.buildMessage(null, + Lists.newArrayList( + Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(MessageClientIDSetter.createUniqID()) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build(), + Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC + 2) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(MessageClientIDSetter.createUniqID()) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build() + ), + Resource.newBuilder().setName(TOPIC).build()); + } + + @Test + public void testBuildMessage() { + long deliveryTime = System.currentTimeMillis(); + String msgId = MessageClientIDSetter.createUniqID(); + + MessageExt messageExt = this.sendMessageActivity.buildMessage(null, + Lists.newArrayList( + Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(msgId) + .setQueueId(0) + .setMessageType(MessageType.DELAY) + .setDeliveryTimestamp(Timestamps.fromMillis(deliveryTime)) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build() + ), + Resource.newBuilder().setName(TOPIC).build()).get(0); + + assertEquals(MessageClientIDSetter.getUniqID(messageExt), msgId); + assertEquals(String.valueOf(deliveryTime), messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS)); + } + + @Test + public void testTxMessage() { + String msgId = MessageClientIDSetter.createUniqID(); + + MessageExt messageExt = this.sendMessageActivity.buildMessage(null, + Lists.newArrayList( + Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(msgId) + .setQueueId(0) + .setMessageType(MessageType.TRANSACTION) + .setOrphanedTransactionRecoveryDuration(Durations.fromSeconds(30)) + .setBodyEncoding(Encoding.GZIP) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build() + ), + Resource.newBuilder().setName(TOPIC).build()).get(0); + + assertEquals(MessageClientIDSetter.getUniqID(messageExt), msgId); + assertEquals(MessageSysFlag.TRANSACTION_PREPARED_TYPE | MessageSysFlag.COMPRESSED_FLAG, messageExt.getSysFlag()); + } +} \ No newline at end of file From 4ee1a9de76dc9b850e075d8e4b014134c3017c72 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Thu, 19 May 2022 16:23:32 +0800 Subject: [PATCH 190/338] [ISSUE #3949] improve readability. --- .../org/apache/rocketmq/proxy/ProxyStartup.java | 15 ++++++++------- .../apache/rocketmq/proxy/config/ProxyConfig.java | 13 +++++++------ .../proxy/grpc/v2/channel/GrpcChannelManager.java | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) 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 22637f9981..d198830e30 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -80,18 +80,18 @@ public class ProxyStartup { try { PROXY_START_AND_SHUTDOWN.shutdown(); } catch (Exception e) { - log.error("err when shutdown rmq-proxy", e); + log.error("err when shutdown rocketmq-proxy", e); } })); } catch (Exception e) { - System.err.println("find a unexpect err." + e); + System.err.println("find an unexpect err." + e); e.printStackTrace(); - log.error("find a unexpect err.", e); + log.error("find an unexpect err.", e); System.exit(1); } - System.out.printf("%s%n", new Date() + " rmq-proxy startup successfully"); - log.info(new Date() + " rmq-proxy startup successfully"); + System.out.printf("%s%n", new Date() + " rocketmq-proxy startup successfully"); + log.info(new Date() + " rocketmq-proxy startup successfully"); } private static MessagingProcessor createMessagingProcessor() { @@ -134,8 +134,9 @@ public class ProxyStartup { } public static ThreadPoolExecutor createServerExecutor() { - int threadPoolNums = ConfigurationManager.getProxyConfig().getGrpcThreadPoolNums(); - int threadPoolQueueCapacity = ConfigurationManager.getProxyConfig().getGrpcThreadPoolQueueCapacity(); + ProxyConfig config = ConfigurationManager.getProxyConfig(); + int threadPoolNums = config.getGrpcThreadPoolNums(); + int threadPoolQueueCapacity = config.getGrpcThreadPoolQueueCapacity(); ThreadPoolExecutor executor = ThreadPoolMonitor.createAndMonitor( threadPoolNums, threadPoolNums, 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 6d56457a14..2127a6c0f7 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 @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.config; +import java.time.Duration; import org.apache.rocketmq.proxy.ProxyMode; public class ProxyConfig { @@ -29,7 +30,7 @@ public class ProxyConfig { * configuration for ThreadPoolMonitor */ private boolean enablePrintJstack = true; - private long printJstackInMillis = 60000; + private long printJstackInMillis = Duration.ofSeconds(60).toMillis(); private String nameSrvAddr = ""; private String nameSrvDomain = ""; @@ -58,7 +59,7 @@ public class ProxyConfig { private int rocketmqMQClientNum = 6; - private long grpcProxyOutRequestTimeoutSecond = 5; + private long grpcProxyRelayRequestTimeoutInSeconds = 5; private int grpcProducerThreadPoolNums = PROCESSOR_NUMBER; private int grpcProducerThreadQueueCapacity = 10000; private int grpcConsumerThreadPoolNums = PROCESSOR_NUMBER; @@ -258,12 +259,12 @@ public class ProxyConfig { this.rocketmqMQClientNum = rocketmqMQClientNum; } - public long getGrpcProxyOutRequestTimeoutSecond() { - return grpcProxyOutRequestTimeoutSecond; + public long getGrpcProxyRelayRequestTimeoutInSeconds() { + return grpcProxyRelayRequestTimeoutInSeconds; } - public void setGrpcProxyOutRequestTimeoutSecond(long grpcProxyOutRequestTimeoutSecond) { - this.grpcProxyOutRequestTimeoutSecond = grpcProxyOutRequestTimeoutSecond; + public void setGrpcProxyRelayRequestTimeoutInSeconds(long grpcProxyRelayRequestTimeoutInSeconds) { + this.grpcProxyRelayRequestTimeoutInSeconds = grpcProxyRelayRequestTimeoutInSeconds; } public int getGrpcProducerThreadPoolNums() { 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 262c83fd01..fd07618c45 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 @@ -109,7 +109,7 @@ public class GrpcChannelManager implements StartAndShutdown { protected void scanExpireResultFuture() { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - long timeOutMs = TimeUnit.SECONDS.toMillis(proxyConfig.getGrpcProxyOutRequestTimeoutSecond()); + long timeOutMs = TimeUnit.SECONDS.toMillis(proxyConfig.getGrpcProxyRelayRequestTimeoutInSeconds()); Set nonceSet = this.resultNonceFutureMap.keySet(); for (String nonce : nonceSet) { From bc86a2ea9a5ec59628f753c373bd586fa8339c15 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 23 May 2022 16:12:42 +0800 Subject: [PATCH 191/338] [ISSUE #3949] change sendResult to list of sendResult; return MULTIPLE_RESULTS when has multiple response code --- .../grpc/v2/consumer/AckMessageActivity.java | 18 ++++- .../grpc/v2/producer/SendMessageActivity.java | 80 ++++++++++++------- .../processor/DefaultMessagingProcessor.java | 2 +- .../proxy/processor/MessagingProcessor.java | 4 +- .../proxy/processor/ProducerProcessor.java | 22 ++++- .../message/AbstractMessageService.java | 44 ---------- .../message/ClusterMessageService.java | 15 ++-- .../service/message/LocalMessageService.java | 4 +- .../proxy/service/message/MessageService.java | 2 +- .../v2/consumer/AckMessageActivityTest.java | 2 +- .../v2/producer/SendMessageActivityTest.java | 71 ++++++++++------ .../processor/ProducerProcessorTest.java | 25 +++++- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 4 +- 13 files changed, 170 insertions(+), 123 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java 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 7226717a73..65c4f4fb3d 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 @@ -23,7 +23,9 @@ import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.Code; import io.grpc.Context; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; @@ -34,6 +36,7 @@ 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.MessagingProcessor; +import org.checkerframework.checker.units.qual.C; public class AckMessageActivity extends AbstractMessingActivity { @@ -56,13 +59,24 @@ public class AckMessageActivity extends AbstractMessingActivity { future.completeExceptionally(throwable); return; } + + Set responseCodes = new HashSet<>(); List entryList = new ArrayList<>(); for (CompletableFuture entryFuture : futures) { - entryFuture.thenAccept(entryList::add); + AckMessageResultEntry entryResult = entryFuture.join(); + responseCodes.add(entryResult.getStatus().getCode()); + entryList.add(entryResult); } AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .addAllEntries(entryList); + if (responseCodes.size() > 1) { + responseBuilder.setStatus(ResponseBuilder.buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name())); + } else if (responseCodes.size() == 1) { + Code code = responseCodes.stream().findAny().get(); + responseBuilder.setStatus(ResponseBuilder.buildStatus(code, code.name())); + } else { + responseBuilder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message result is empty")); + } future.complete(responseBuilder.build()); }); } catch (Throwable t) { 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 249630a224..998c0276fb 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 @@ -23,9 +23,8 @@ import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.SendReceipt; +import apache.rocketmq.v2.SendResultEntry; import apache.rocketmq.v2.SystemProperties; -import com.beust.jcommander.internal.Lists; import com.google.common.collect.Maps; import com.google.common.hash.Hashing; import com.google.protobuf.Duration; @@ -34,8 +33,10 @@ import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; import io.grpc.Context; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; @@ -190,35 +191,54 @@ public class SendMessageActivity extends AbstractMessingActivity { } protected SendMessageResponse convertToSendMessageResponse(ProxyContext ctx, SendMessageRequest request, - SendResult result) { - switch (result.getSendStatus()) { - case FLUSH_DISK_TIMEOUT: - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.MASTER_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); - case FLUSH_SLAVE_TIMEOUT: - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.SLAVE_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); - case SLAVE_NOT_AVAILABLE: - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.HA_NOT_AVAILABLE, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); - case SEND_OK: - List sendReceiptList = Lists.newArrayList(); - sendReceiptList.add(SendReceipt.newBuilder() - .setMessageId(StringUtils.defaultString(result.getMsgId())) - .setTransactionId(StringUtils.defaultString(result.getTransactionId())) - .build()); - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .addAllReceipts(sendReceiptList) - .build(); - default: - return SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) - .build(); + List resultList) { + SendMessageResponse.Builder builder = SendMessageResponse.newBuilder(); + + Set responseCodes = new HashSet<>(); + for (SendResult result : resultList) { + SendResultEntry resultEntry; + switch (result.getSendStatus()) { + case FLUSH_DISK_TIMEOUT: + resultEntry = SendResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.MASTER_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + break; + case FLUSH_SLAVE_TIMEOUT: + resultEntry = SendResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.SLAVE_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + break; + case SLAVE_NOT_AVAILABLE: + resultEntry = SendResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.HA_NOT_AVAILABLE, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + break; + case SEND_OK: + resultEntry = SendResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setOffset(result.getQueueOffset()) + .setMessageId(StringUtils.defaultString(result.getMsgId())) + .setTransactionId(StringUtils.defaultString(result.getTransactionId())) + .build(); + break; + default: + resultEntry = SendResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) + .build(); + break; + } + builder.addEntries(resultEntry); + responseCodes.add(resultEntry.getStatus().getCode()); } + if (responseCodes.size() > 1) { + builder.setStatus(ResponseBuilder.buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name())); + } else if (responseCodes.size() == 1) { + Code code = responseCodes.stream().findAny().get(); + builder.setStatus(ResponseBuilder.buildStatus(code, code.name())); + } else { + builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send status is empty")); + } + return builder.build(); } protected static class SendMessageQueueSelector implements QueueSelector { 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 c159dec05d..44816f1adc 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 @@ -125,7 +125,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public CompletableFuture sendMessage(ProxyContext ctx, QueueSelector queueSelector, + public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector, String producerGroup, List msg, long timeoutMillis) { return this.producerProcessor.sendMessage(ctx, queueSelector, producerGroup, msg, 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 eee9f98731..1932c3f83b 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 @@ -59,7 +59,7 @@ public interface MessagingProcessor extends StartAndShutdown { String topicName ) throws Exception; - default CompletableFuture sendMessage( + default CompletableFuture> sendMessage( ProxyContext ctx, QueueSelector queueSelector, String producerGroup, @@ -68,7 +68,7 @@ public interface MessagingProcessor extends StartAndShutdown { return sendMessage(ctx, queueSelector, producerGroup, msg, DEFAULT_TIMEOUT_MILLS); } - CompletableFuture sendMessage( + CompletableFuture> sendMessage( ProxyContext ctx, QueueSelector queueSelector, String producerGroup, 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 086151e96b..a5baf4f9a5 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,7 +19,9 @@ package org.apache.rocketmq.proxy.processor; 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; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageAccessor; @@ -29,12 +31,14 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; 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.utils.FutureUtils; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerProcessor extends AbstractProcessor { @@ -47,9 +51,9 @@ public class ProducerProcessor extends AbstractProcessor { this.executor = executor; } - public CompletableFuture sendMessage(ProxyContext ctx, QueueSelector queueSelector, + public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector, String producerGroup, List messageExtList, long timeoutMillis) { - CompletableFuture future = new CompletableFuture<>(); + CompletableFuture> future = new CompletableFuture<>(); try { String topic = messageExtList.get(0).getTopic(); SelectableMessageQueue messageQueue = queueSelector.select(ctx, @@ -65,7 +69,19 @@ public class ProducerProcessor extends AbstractProcessor { messageQueue, messageExtList, requestHeader, - timeoutMillis); + timeoutMillis) + .thenApplyAsync(sendResultList -> { + for (SendResult sendResult : sendResultList) { + int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && + tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && + StringUtils.isNotBlank(sendResult.getTransactionId())) { + TransactionId transactionId = TransactionId.genByBrokerTransactionId(messageQueue.getBrokerName(), sendResult); + sendResult.setTransactionId(transactionId.getProxyTransactionId()); + } + } + return sendResultList; + }, this.executor); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java deleted file mode 100644 index b7aa35ae84..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/AbstractMessageService.java +++ /dev/null @@ -1,44 +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.proxy.service.message; - -import java.util.concurrent.CompletableFuture; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; - -public abstract class AbstractMessageService implements MessageService { - - protected CompletableFuture processSendMessageResponseFuture( - String brokerName, - SendMessageRequestHeader requestHeader, - CompletableFuture future) { - return future.thenApply(sendResult -> { - int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && - tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && - StringUtils.isNotBlank(sendResult.getTransactionId())) { - TransactionId transactionId = TransactionId.genByBrokerTransactionId(brokerName, sendResult); - sendResult.setTransactionId(transactionId.getProxyTransactionId()); - } - return sendResult; - }); - } -} 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 b48cade6da..4fc8fdad9e 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 @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service.message; +import com.google.common.collect.Lists; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; @@ -40,7 +41,7 @@ import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class ClusterMessageService extends AbstractMessageService { +public class ClusterMessageService implements MessageService { private final TopicRouteService topicRouteService; private final MQClientAPIFactory mqClientAPIFactory; @@ -51,19 +52,21 @@ public class ClusterMessageService extends AbstractMessageService { } @Override - public CompletableFuture sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { - CompletableFuture future; + CompletableFuture> future; if (msgList.size() == 1) { future = this.mqClientAPIFactory.getClient().sendMessageAsync( messageQueue.getBrokerAddr(), - messageQueue.getBrokerName(), msgList.get(0), requestHeader, timeoutMillis); + messageQueue.getBrokerName(), msgList.get(0), requestHeader, timeoutMillis) + .thenApply(Lists::newArrayList); } else { future = this.mqClientAPIFactory.getClient().sendMessageAsync( messageQueue.getBrokerAddr(), - messageQueue.getBrokerName(), msgList, requestHeader, timeoutMillis); + messageQueue.getBrokerName(), msgList, requestHeader, timeoutMillis) + .thenApply(Lists::newArrayList); } - return processSendMessageResponseFuture(messageQueue.getBrokerName(), requestHeader, future); + return future; } @Override 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 e8ff4a353c..055f9e85e1 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 @@ -36,7 +36,7 @@ import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class LocalMessageService extends AbstractMessageService { +public class LocalMessageService implements MessageService { private BrokerController brokerController; @@ -44,7 +44,7 @@ public class LocalMessageService extends AbstractMessageService { this.brokerController = brokerController; } - @Override public CompletableFuture sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + @Override public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { return null; } 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 4d42c317cb..35f0ea147b 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 @@ -38,7 +38,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface MessageService { - CompletableFuture sendMessage( + CompletableFuture> sendMessage( ProxyContext ctx, SelectableMessageQueue messageQueue, List msgList, 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 353b145fba..6ca311d6ff 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 @@ -82,7 +82,7 @@ public class AckMessageActivityTest extends BaseActivityTest { .build() ).get(); - assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode()); assertEquals(3, response.getEntriesCount()); assertEquals(Code.RECEIPT_HANDLE_EXPIRED, response.getEntries(0).getStatus().getCode()); assertEquals(Code.OK, response.getEntries(1).getStatus().getCode()); 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 682cf32b6b..a23fdd5612 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 @@ -70,7 +70,7 @@ public class SendMessageActivityTest extends BaseActivityTest { sendResult.setSendStatus(SendStatus.SEND_OK); sendResult.setMsgId(msgId); when(this.messagingProcessor.sendMessage(any(), any(), anyString(), any())) - .thenReturn(CompletableFuture.completedFuture(sendResult)); + .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); SendMessageResponse response = this.sendMessageActivity.sendMessage( createContext(), @@ -92,43 +92,62 @@ public class SendMessageActivityTest extends BaseActivityTest { ).get(); assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(msgId, response.getReceipts(0).getMessageId()); + assertEquals(msgId, response.getEntries(0).getMessageId()); } @Test public void testConvertToSendMessageResponse() { - assertEquals( - Code.MASTER_PERSISTENCE_TIMEOUT, - this.sendMessageActivity.convertToSendMessageResponse( + { + SendMessageResponse response = this.sendMessageActivity.convertToSendMessageResponse( ProxyContext.create(), SendMessageRequest.newBuilder().build(), - new SendResult(SendStatus.FLUSH_DISK_TIMEOUT, null, null, null, 0) - ).getStatus().getCode() - ); - assertEquals( - Code.SLAVE_PERSISTENCE_TIMEOUT, - this.sendMessageActivity.convertToSendMessageResponse( + Lists.newArrayList(new SendResult(SendStatus.FLUSH_DISK_TIMEOUT, null, null, null, 0)) + ); + assertEquals(Code.MASTER_PERSISTENCE_TIMEOUT, response.getStatus().getCode()); + assertEquals(Code.MASTER_PERSISTENCE_TIMEOUT, response.getEntries(0).getStatus().getCode()); + } + + { + SendMessageResponse response = this.sendMessageActivity.convertToSendMessageResponse( ProxyContext.create(), SendMessageRequest.newBuilder().build(), - new SendResult(SendStatus.FLUSH_SLAVE_TIMEOUT, null, null, null, 0) - ).getStatus().getCode() - ); - assertEquals( - Code.HA_NOT_AVAILABLE, - this.sendMessageActivity.convertToSendMessageResponse( + Lists.newArrayList(new SendResult(SendStatus.FLUSH_SLAVE_TIMEOUT, null, null, null, 0)) + ); + assertEquals(Code.SLAVE_PERSISTENCE_TIMEOUT, response.getStatus().getCode()); + assertEquals(Code.SLAVE_PERSISTENCE_TIMEOUT, response.getEntries(0).getStatus().getCode()); + } + + { + SendMessageResponse response = this.sendMessageActivity.convertToSendMessageResponse( ProxyContext.create(), SendMessageRequest.newBuilder().build(), - new SendResult(SendStatus.SLAVE_NOT_AVAILABLE, null, null, null, 0) - ).getStatus().getCode() - ); - assertEquals( - Code.OK, - this.sendMessageActivity.convertToSendMessageResponse( + Lists.newArrayList(new SendResult(SendStatus.SLAVE_NOT_AVAILABLE, null, null, null, 0)) + ); + assertEquals(Code.HA_NOT_AVAILABLE, response.getStatus().getCode()); + assertEquals(Code.HA_NOT_AVAILABLE, response.getEntries(0).getStatus().getCode()); + } + + { + SendMessageResponse response = this.sendMessageActivity.convertToSendMessageResponse( ProxyContext.create(), SendMessageRequest.newBuilder().build(), - new SendResult(SendStatus.SEND_OK, null, null, null, 0) - ).getStatus().getCode() - ); + Lists.newArrayList(new SendResult(SendStatus.SEND_OK, null, null, null, 0)) + ); + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(Code.OK, response.getEntries(0).getStatus().getCode()); + } + + { + SendMessageResponse response = this.sendMessageActivity.convertToSendMessageResponse( + ProxyContext.create(), + SendMessageRequest.newBuilder().build(), + Lists.newArrayList( + new SendResult(SendStatus.SEND_OK, null, null, null, 0), + new SendResult(SendStatus.SLAVE_NOT_AVAILABLE, null, null, null, 0) + ) + ); + assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode()); + } } @Test(expected = GrpcProxyException.class) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 9f138fd562..4bac51a5d8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -22,19 +22,24 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -62,18 +67,27 @@ public class ProducerProcessorTest extends BaseProcessorTest { @Test public void testSendMessage() throws Throwable { + String txId = MessageClientIDSetter.createUniqID(); + String msgId = MessageClientIDSetter.createUniqID(); + + SendResult sendResult = new SendResult(); + sendResult.setSendStatus(SendStatus.SEND_OK); + sendResult.setTransactionId(txId); + sendResult.setMsgId(msgId); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) - .thenReturn(CompletableFuture.completedFuture(mock(SendResult.class))); + .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); List messageExtList = new ArrayList<>(); MessageExt messageExt = createMessageExt(MixAll.getRetryTopic(CONSUMER_GROUP), "tag", 0, 0); + messageExt.setSysFlag(MessageSysFlag.TRANSACTION_PREPARED_TYPE); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_RECONSUME_TIME, "1"); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_MAX_RECONSUME_TIMES, "16"); messageExtList.add(messageExt); SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + when(messageQueue.getBrokerName()).thenReturn("mockBroker"); - SendResult sendResult = this.producerProcessor.sendMessage( + List sendResultList = this.producerProcessor.sendMessage( createContext(), (ctx, messageQueueView) -> messageQueue, PRODUCER_GROUP, @@ -81,7 +95,12 @@ public class ProducerProcessorTest extends BaseProcessorTest { 3000 ).get(); - assertNotNull(sendResult); + assertNotNull(sendResultList); + TransactionId transactionId = TransactionId.decode(sendResultList.get(0).getTransactionId()); + assertNotNull(transactionId); + assertEquals(txId, transactionId.getBrokerTransactionId()); + assertEquals("mockBroker", transactionId.getBrokerName()); + SendMessageRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); assertEquals(PRODUCER_GROUP, requestHeader.getProducerGroup()); assertEquals(MixAll.getRetryTopic(CONSUMER_GROUP), requestHeader.getTopic()); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index efbda29d54..38873fa9e8 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -336,7 +336,7 @@ public class GrpcBaseIT extends BaseConf { AckMessageResponse ackMessageResponse = blockingStub.ackMessage(buildAckMessageRequest(topic, group, AckMessageEntry.newBuilder().setMessageId(messageId).setReceiptHandle(ackHandles.get(0)).build(), AckMessageEntry.newBuilder().setMessageId(messageId).setReceiptHandle(ackHandles.get(1)).build())); - assertThat(ackMessageResponse.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(ackMessageResponse.getStatus().getCode()).isEqualTo(Code.MULTIPLE_RESULTS); int okNum = 0; int expireNum = 0; for (AckMessageResultEntry entry : ackMessageResponse.getEntriesList()) { @@ -550,7 +550,7 @@ public class GrpcBaseIT extends BaseConf { public void assertSendMessage(SendMessageResponse response, String messageId) { assertThat(response.getStatus() .getCode()).isEqualTo(Code.OK); - assertThat(response.getReceipts(0).getMessageId()).isEqualTo(messageId); + assertThat(response.getEntries(0).getMessageId()).isEqualTo(messageId); } public Message assertAndGetReceiveMessage(List response, String messageId) { From 0b34b0add71b34e09a05747bcc9b54dbea966f08 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 18 May 2022 17:14:53 +0800 Subject: [PATCH 192/338] [ISSUE #3949] Add LocalProxyRelayService implementation --- .../proxy/common/ContextVariable.java | 23 ++ .../grpc/v2/channel/GrpcClientChannel.java | 8 +- .../proxy/service/channel/SimpleChannel.java | 168 ++++++++++++ .../channel/SimpleChannelHandlerContext.java | 246 ++++++++++++++++++ .../relay/ClusterProxyRelayService.java | 7 +- .../service/relay/LocalProxyRelayService.java | 15 +- .../proxy/service/relay/ProxyChannel.java | 21 +- .../service/relay/ProxyRelayService.java | 3 + 8 files changed, 474 insertions(+), 17 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannelHandlerContext.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java new file mode 100644 index 0000000000..fcc6bb02ff --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -0,0 +1,23 @@ +/* + * 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.common; + +public class ContextVariable { + public final static String REMOTE_ADDRESS = "remote-address"; + public final static String LOCAL_ADDRESS = "local-address"; +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index eb3e8c9b47..2f629db4cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -51,14 +51,12 @@ public class GrpcClientChannel extends ProxyChannel { private final AtomicReference> telemetryCommandRef = new AtomicReference<>(); private final String group; private final String clientId; - private final String remoteAddress; - private final String localAddress; public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, Context ctx, String group, String clientId) { - super(proxyRelayService, null, new GrpcChannelId(group, clientId)); + super(proxyRelayService, null, new GrpcChannelId(group, clientId), + InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS), + InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)); this.grpcChannelManager = grpcChannelManager; - this.remoteAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS); - this.localAddress = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS); this.group = group; this.clientId = clientId; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java new file mode 100644 index 0000000000..3e2ea4562a --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java @@ -0,0 +1,168 @@ +/* + * 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.service.channel; + +import com.google.common.base.Strings; +import io.netty.channel.AbstractChannel; +import io.netty.channel.Channel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelMetadata; +import io.netty.channel.ChannelOutboundBuffer; +import io.netty.channel.DefaultChannelPromise; +import io.netty.channel.EventLoop; +import io.netty.util.concurrent.GlobalEventExecutor; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; + +/** + * SimpleChannel is used to handle writeAndFlush situation in processor + * @see io.netty.channel.ChannelHandlerContext#writeAndFlush + * @see io.netty.channel.Channel#writeAndFlush + */ +public class SimpleChannel extends AbstractChannel { + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + protected final String remoteAddress; + protected final String localAddress; + + protected long lastAccessTime; + + /** + * Creates a new instance. + * + * @param parent the parent of this channel. {@code null} if there's no parent. + * @param remoteAddress Remote address + * @param localAddress Local address + */ + public SimpleChannel(Channel parent, String remoteAddress, String localAddress) { + super(parent); + lastAccessTime = System.currentTimeMillis(); + this.remoteAddress = remoteAddress; + this.localAddress = localAddress; + } + + public SimpleChannel(String remoteAddress, String localAddress) { + this(null, remoteAddress, localAddress); + } + + @Override + protected AbstractUnsafe newUnsafe() { + return null; + } + + @Override + protected boolean isCompatible(EventLoop loop) { + return false; + } + + private static SocketAddress parseSocketAddress(String address) { + if (Strings.isNullOrEmpty(address)) { + return null; + } + + String[] segments = address.split(":"); + if (2 == segments.length) { + return new InetSocketAddress(segments[0], Integer.parseInt(segments[1])); + } + + return null; + } + + @Override + protected SocketAddress localAddress0() { + return parseSocketAddress(localAddress); + } + + @Override + public SocketAddress localAddress() { + return localAddress0(); + } + + @Override + public SocketAddress remoteAddress() { + return remoteAddress0(); + } + + @Override + protected SocketAddress remoteAddress0() { + return parseSocketAddress(remoteAddress); + } + + @Override + protected void doBind(SocketAddress localAddress) throws Exception { + + } + + @Override + protected void doDisconnect() throws Exception { + + } + + @Override + public ChannelFuture close() { + DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); + promise.setSuccess(); + return promise; + } + + @Override + protected void doClose() throws Exception { + + } + + @Override + protected void doBeginRead() throws Exception { + + } + + @Override + protected void doWrite(ChannelOutboundBuffer in) throws Exception { + + } + + @Override + public ChannelConfig config() { + return null; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public boolean isActive() { + return (System.currentTimeMillis() - lastAccessTime) <= 120L * 1000; + } + + @Override + public ChannelMetadata metadata() { + return null; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); + promise.setSuccess(); + return promise; + } +} \ No newline at end of file diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannelHandlerContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannelHandlerContext.java new file mode 100644 index 0000000000..801c62ee5f --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannelHandlerContext.java @@ -0,0 +1,246 @@ +/* + * 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.service.channel; + +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelProgressivePromise; +import io.netty.channel.ChannelPromise; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.concurrent.EventExecutor; +import java.net.SocketAddress; +import org.apache.commons.lang3.NotImplementedException; + +public class SimpleChannelHandlerContext implements ChannelHandlerContext { + + private final Channel channel; + + public SimpleChannelHandlerContext(Channel channel) { + this.channel = channel; + } + + @Override + public Channel channel() { + return channel; + } + + @Override + public EventExecutor executor() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public String name() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandler handler() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public boolean isRemoved() { + return false; + } + + @Override + public ChannelHandlerContext fireChannelRegistered() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelUnregistered() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelActive() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelInactive() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireExceptionCaught(Throwable cause) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireUserEventTriggered(Object evt) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelRead(Object msg) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelReadComplete() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext fireChannelWritabilityChanged() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture disconnect() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture close() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture deregister() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture disconnect(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture close(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture deregister(ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext read() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture write(Object msg) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture write(Object msg, ChannelPromise promise) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelHandlerContext flush() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { + return channel.writeAndFlush(msg, promise); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + return channel.writeAndFlush(msg); + } + + @Override + public ChannelPipeline pipeline() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ByteBufAllocator alloc() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelPromise newPromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelProgressivePromise newProgressivePromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture newSucceededFuture() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelFuture newFailedFuture(Throwable cause) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public ChannelPromise voidPromise() { + throw new NotImplementedException("Not implemented"); + } + + @Override + public Attribute attr(AttributeKey key) { + throw new NotImplementedException("Not implemented"); + } + + @Override + public boolean hasAttr(AttributeKey attributeKey) { + return false; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java index 4db1a84540..9b356e788b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java @@ -21,6 +21,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.remoting.protocol.RemotingCommand; /** @@ -29,13 +30,15 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ClusterProxyRelayService implements ProxyRelayService { @Override - public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, + public CompletableFuture> processGetConsumerRunningInfo( + ProxyContext context, RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { return null; } @Override public CompletableFuture> processConsumeMessageDirectly( - RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { + ProxyContext context, RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header) { return null; } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index 8ecb6988d2..c39cc3f262 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -23,6 +23,10 @@ import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.common.ContextVariable; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.channel.SimpleChannel; +import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -36,8 +40,8 @@ public class LocalProxyRelayService implements ProxyRelayService { } @Override - public CompletableFuture> processGetConsumerRunningInfo(RemotingCommand command, - GetConsumerRunningInfoRequestHeader header) { + public CompletableFuture> processGetConsumerRunningInfo( + ProxyContext context, RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { CompletableFuture> future = new CompletableFuture<>(); future.thenAccept(proxyOutResult -> { if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { @@ -50,8 +54,8 @@ public class LocalProxyRelayService implements ProxyRelayService { ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); runningInfo.setJstack(consumerRunningInfo.getJstack()); remotingCommand.setBody(runningInfo.encode()); - - // nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); + SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(simpleChannel), remotingCommand); } } }); @@ -59,7 +63,8 @@ public class LocalProxyRelayService implements ProxyRelayService { } @Override - public CompletableFuture> processConsumeMessageDirectly(RemotingCommand command, + public CompletableFuture> processConsumeMessageDirectly( + ProxyContext context, RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { return null; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 153ffb709f..157bcd63ba 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -41,22 +41,30 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.ContextVariable; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public abstract class ProxyChannel extends AbstractChannel { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected final String remoteAddress; + protected final String localAddress; protected final ProxyRelayService proxyRelayService; - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, String localAddress) { super(parent); this.proxyRelayService = proxyRelayService; + this.remoteAddress = remoteAddress; + this.localAddress = localAddress; } - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, String localAddress) { super(parent, id); this.proxyRelayService = proxyRelayService; + this.remoteAddress = remoteAddress; + this.localAddress = localAddress; } @Override @@ -65,6 +73,9 @@ public abstract class ProxyChannel extends AbstractChannel { try { if (msg instanceof RemotingCommand) { + ProxyContext context = ProxyContext.create() + .withVal(ContextVariable.REMOTE_ADDRESS, remoteAddress) + .withVal(ContextVariable.REMOTE_ADDRESS, localAddress); RemotingCommand command = (RemotingCommand) msg; switch (command.getCode()) { case RequestCode.CHECK_TRANSACTION_STATE: { @@ -77,15 +88,15 @@ public abstract class ProxyChannel extends AbstractChannel { } case RequestCode.GET_CONSUMER_RUNNING_INFO: { GetConsumerRunningInfoRequestHeader header = (GetConsumerRunningInfoRequestHeader) command.readCustomHeader(); - processFuture = this.processGetConsumerRunningInfo(command, header, - this.proxyRelayService.processGetConsumerRunningInfo(command, header)); + CompletableFuture> relayFuture = this.proxyRelayService.processGetConsumerRunningInfo(context, command, header); + processFuture = this.processGetConsumerRunningInfo(command, header, relayFuture); break; } case RequestCode.CONSUME_MESSAGE_DIRECTLY: { ConsumeMessageDirectlyResultRequestHeader header = (ConsumeMessageDirectlyResultRequestHeader) command.readCustomHeader(); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); processFuture = this.processConsumeMessageDirectly(command, header, messageExt, - this.proxyRelayService.processConsumeMessageDirectly(command, header)); + this.proxyRelayService.processConsumeMessageDirectly(context, command, header)); break; } default: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java index 1e800206a3..b7284da1c0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java @@ -21,16 +21,19 @@ import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface ProxyRelayService { CompletableFuture> processGetConsumerRunningInfo( + ProxyContext context, RemotingCommand command, GetConsumerRunningInfoRequestHeader header ); CompletableFuture> processConsumeMessageDirectly( + ProxyContext context, RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header ); From 0ad9b3adb19ae30ee293edbc922ac7ac72b76c9f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 18 May 2022 18:55:24 +0800 Subject: [PATCH 193/338] [ISSUE #3949] Remove backup code --- .../backup/channel/InvocationChannel.java | 83 -- .../backup/channel/InvocationContext.java | 48 -- .../backup/channel/SimpleChannel.java | 180 ----- .../channel/SimpleChannelHandlerContext.java | 247 ------ .../backup/grpc/v2/adapter/GrpcConverter.java | 733 ------------------ .../grpc/v2/adapter/ProxyException.java | 38 - .../backup/grpc/v2/adapter/ProxyMode.java | 57 -- .../grpc/v2/adapter/RequestMapping.java | 57 -- .../backup/grpc/v2/adapter/ResponseHook.java | 24 - .../channel/ReceiveMessageChannel.java | 31 - .../adapter/channel/SendMessageChannel.java | 30 - .../ReceiveMessageResponseHandler.java | 146 ---- .../v2/adapter/handler/ResponseHandler.java | 25 - .../handler/SendMessageResponseHandler.java | 84 -- .../grpc/v2/service/AbstractRouteService.java | 99 --- ...aseReceiveMessageResponseStreamWriter.java | 122 --- .../BaseReceiveMessageResultFilter.java | 67 -- .../backup/grpc/v2/service/BaseService.java | 77 -- .../v2/service/ClientSettingsService.java | 65 -- .../grpc/v2/service/ClusterGrpcActivity.java | 184 ----- .../grpc/v2/service/LocalGrpcActivity.java | 566 -------------- .../ReceiveMessageResponseStreamObserver.java | 67 -- .../service/ReceiveMessageResultFilter.java | 29 - .../cluster/AssignmentQueueSelector.java | 27 - .../v2/service/cluster/ConsumerService.java | 283 ------- .../DefaultAssignmentQueueSelector.java | 41 - .../cluster/DefaultReadQueueSelector.java | 55 -- ...ultReceiveMessageResponseStreamWriter.java | 96 --- .../DefaultReceiveMessageResultFilter.java | 127 --- .../cluster/DefaultWriteQueueSelector.java | 77 -- .../service/cluster/ForwardClientService.java | 266 ------- .../v2/service/cluster/ProducerService.java | 184 ----- .../v2/service/cluster/ReadQueueSelector.java | 27 - .../grpc/v2/service/cluster/RouteService.java | 150 ---- .../service/cluster/TransactionService.java | 139 ---- .../service/cluster/WriteQueueSelector.java | 26 - ...calReceiveMessageResponseStreamWriter.java | 76 -- .../LocalReceiveMessageResultFilter.java | 94 --- .../local/LocalWriteQueueSelector.java | 101 --- .../grpc/v2/service/local/RouteService.java | 175 ----- .../grpc/v2/service/LocalGrpcServiceTest.java | 524 ------------- .../v2/service/cluster/BaseServiceTest.java | 132 ---- .../service/cluster/ConsumerServiceTest.java | 274 ------- .../cluster/DefaultReadQueueSelectorTest.java | 89 --- .../DefaultWriteQueueSelectorTest.java | 94 --- .../cluster/ForwardClientServiceTest.java | 142 ---- .../service/cluster/ProducerServiceTest.java | 163 ---- .../v2/service/cluster/RouteServiceTest.java | 251 ------ .../cluster/TransactionServiceTest.java | 104 --- .../LocalPopMessageResultFilterTest.java | 135 ---- ...eceiveMessageResponseStreamWriterTest.java | 170 ---- .../local/LocalWriteQueueSelectorTest.java | 78 -- .../v2/service/local/RouteServiceTest.java | 132 ---- .../service/ForwardClientManagerTest.java | 55 -- 54 files changed, 7346 deletions(-) delete mode 100644 proxy/src/test/resources/backup/channel/InvocationChannel.java delete mode 100644 proxy/src/test/resources/backup/channel/InvocationContext.java delete mode 100644 proxy/src/test/resources/backup/channel/SimpleChannel.java delete mode 100644 proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/BaseService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java delete mode 100644 proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java delete mode 100644 proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java diff --git a/proxy/src/test/resources/backup/channel/InvocationChannel.java b/proxy/src/test/resources/backup/channel/InvocationChannel.java deleted file mode 100644 index 4d537f740b..0000000000 --- a/proxy/src/test/resources/backup/channel/InvocationChannel.java +++ /dev/null @@ -1,83 +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.proxy.channel; -// -//import io.grpc.Context; -//import io.netty.channel.ChannelFuture; -//import java.util.Iterator; -//import java.util.Map; -//import java.util.concurrent.ConcurrentHashMap; -//import java.util.concurrent.ConcurrentMap; -//import org.apache.rocketmq.proxy.common.Cleaner; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ResponseHandler; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -// -//public abstract class InvocationChannel extends SimpleChannel implements Cleaner { -// protected final ConcurrentMap> inFlightRequestMap; -// protected final ResponseHandler handler; -// -// public InvocationChannel(Context ctx, ResponseHandler handler) { -// super(ChannelManager.createSimpleChannelDirectly(ctx)); -// this.inFlightRequestMap = new ConcurrentHashMap<>(); -// this.handler = handler; -// } -// -// @Override -// public ChannelFuture writeAndFlush(Object msg) { -// if (msg instanceof RemotingCommand) { -// RemotingCommand responseCommand = (RemotingCommand) msg; -// InvocationContext context = inFlightRequestMap.remove(responseCommand.getOpaque()); -// if (null != context) { -// handler.handle(responseCommand, context); -// } -// inFlightRequestMap.remove(responseCommand.getOpaque()); -// } -// return super.writeAndFlush(msg); -// } -// -// @Override -// public boolean isWritable() { -// return inFlightRequestMap.size() > 0; -// } -// -// public void registerInvocationContext(int opaque, InvocationContext context) { -// inFlightRequestMap.put(opaque, context); -// } -// -// public void eraseInvocationContext(int opaque) { -// inFlightRequestMap.remove(opaque); -// } -// -// @Override -// public void clean() { -// Iterator>> iterator = inFlightRequestMap.entrySet().iterator(); -// int count = 0; -// while (iterator.hasNext()) { -// Map.Entry> entry = iterator.next(); -// if (entry.getValue().expired(expiredTimeSec)) { -// iterator.remove(); -// count++; -// log.debug("An expired request is found, created time-point: {}, Request: {}", -// entry.getValue().getTimestamp(), entry.getValue().getRequest()); -// } -// } -// if (count > 0) { -// log.warn("[BUG] {} expired in-flight requests is cleaned.", count); -// } -// } -//} diff --git a/proxy/src/test/resources/backup/channel/InvocationContext.java b/proxy/src/test/resources/backup/channel/InvocationContext.java deleted file mode 100644 index 99b6d1f1b1..0000000000 --- a/proxy/src/test/resources/backup/channel/InvocationContext.java +++ /dev/null @@ -1,48 +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.proxy.channel; - -import java.time.Duration; -import java.util.concurrent.CompletableFuture; - -public class InvocationContext { - private final R request; - private final CompletableFuture response; - private final long timestamp = System.currentTimeMillis(); - - public InvocationContext(R req, CompletableFuture resp) { - request = req; - response = resp; - } - - public boolean expired(long expiredTimeSec) { - return System.currentTimeMillis() - timestamp >= Duration.ofSeconds(expiredTimeSec).toMillis(); - } - - public R getRequest() { - return request; - } - - public CompletableFuture getResponse() { - return response; - } - - public long getTimestamp() { - return timestamp; - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/channel/SimpleChannel.java b/proxy/src/test/resources/backup/channel/SimpleChannel.java deleted file mode 100644 index da9c7fb47e..0000000000 --- a/proxy/src/test/resources/backup/channel/SimpleChannel.java +++ /dev/null @@ -1,180 +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 backup.channel; - -import com.google.common.base.Strings; -import io.netty.channel.AbstractChannel; -import io.netty.channel.Channel; -import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelMetadata; -import io.netty.channel.ChannelOutboundBuffer; -import io.netty.channel.DefaultChannelPromise; -import io.netty.channel.EventLoop; -import io.netty.util.concurrent.GlobalEventExecutor; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; - -/** - * SimpleChannel is used to handle writeAndFlush situation in processor - * @see io.netty.channel.ChannelHandlerContext#writeAndFlush - * @see io.netty.channel.Channel#writeAndFlush - */ -public class SimpleChannel extends AbstractChannel { - protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - protected final String remoteAddress; - protected final String localAddress; - protected final long expiredTimeSec; - - protected long lastAccessTime; - - /** - * Creates a new instance. - * - * @param parent the parent of this channel. {@code null} if there's no parent. - * @param remoteAddress Remote address - * @param localAddress Local address - * @param expiredTimeSec Expired time second for cleaning channel - */ - public SimpleChannel(Channel parent, String remoteAddress, String localAddress, long expiredTimeSec) { - super(parent); - lastAccessTime = System.currentTimeMillis(); - this.remoteAddress = remoteAddress; - this.localAddress = localAddress; - this.expiredTimeSec = expiredTimeSec; - } - - public SimpleChannel(SimpleChannel other) { - super(other); - lastAccessTime = other.lastAccessTime; - this.remoteAddress = other.remoteAddress; - this.localAddress = other.localAddress; - this.expiredTimeSec = other.expiredTimeSec; - } - - @Override - protected AbstractUnsafe newUnsafe() { - return null; - } - - @Override - protected boolean isCompatible(EventLoop loop) { - return false; - } - - private static SocketAddress parseSocketAddress(String address) { - if (Strings.isNullOrEmpty(address)) { - return null; - } - - String[] segments = address.split(":"); - if (2 == segments.length) { - return new InetSocketAddress(segments[0], Integer.parseInt(segments[1])); - } - - return null; - } - - @Override - protected SocketAddress localAddress0() { - return parseSocketAddress(localAddress); - } - - @Override - public SocketAddress localAddress() { - return localAddress0(); - } - - @Override - public SocketAddress remoteAddress() { - return remoteAddress0(); - } - - @Override - protected SocketAddress remoteAddress0() { - return parseSocketAddress(remoteAddress); - } - - @Override - protected void doBind(SocketAddress localAddress) throws Exception { - - } - - @Override - protected void doDisconnect() throws Exception { - - } - - @Override - public ChannelFuture close() { - DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); - promise.setSuccess(); - return promise; - } - - @Override - protected void doClose() throws Exception { - - } - - @Override - protected void doBeginRead() throws Exception { - - } - - @Override - protected void doWrite(ChannelOutboundBuffer in) throws Exception { - - } - - @Override - public ChannelConfig config() { - return null; - } - - @Override - public boolean isOpen() { - return true; - } - - @Override - public boolean isActive() { - return (System.currentTimeMillis() - lastAccessTime) <= 120L * 1000; - } - - @Override - public ChannelMetadata metadata() { - return null; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - DefaultChannelPromise promise = new DefaultChannelPromise(this, GlobalEventExecutor.INSTANCE); - promise.setSuccess(); - return promise; - } - - public void updateLastAccessTime() { - lastAccessTime = System.currentTimeMillis(); - } -} - diff --git a/proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java b/proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java deleted file mode 100644 index 1811996a94..0000000000 --- a/proxy/src/test/resources/backup/channel/SimpleChannelHandlerContext.java +++ /dev/null @@ -1,247 +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 backup.channel; - -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelProgressivePromise; -import io.netty.channel.ChannelPromise; -import io.netty.util.Attribute; -import io.netty.util.AttributeKey; -import io.netty.util.concurrent.EventExecutor; -import java.net.SocketAddress; -import org.apache.commons.lang3.NotImplementedException; - -public class SimpleChannelHandlerContext implements ChannelHandlerContext { - - private final Channel channel; - - public SimpleChannelHandlerContext(Channel channel) { - this.channel = channel; - } - - @Override - public Channel channel() { - return channel; - } - - @Override - public EventExecutor executor() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public String name() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandler handler() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public boolean isRemoved() { - return false; - } - - @Override - public ChannelHandlerContext fireChannelRegistered() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelUnregistered() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelActive() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelInactive() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireExceptionCaught(Throwable cause) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireUserEventTriggered(Object evt) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelRead(Object msg) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelReadComplete() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext fireChannelWritabilityChanged() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture bind(SocketAddress localAddress) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture disconnect() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture close() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture deregister() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture disconnect(ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture close(ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture deregister(ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext read() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture write(Object msg) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture write(Object msg, ChannelPromise promise) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelHandlerContext flush() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { - return channel.writeAndFlush(msg, promise); - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - return channel.writeAndFlush(msg); - } - - @Override - public ChannelPipeline pipeline() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ByteBufAllocator alloc() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelPromise newPromise() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelProgressivePromise newProgressivePromise() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture newSucceededFuture() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelFuture newFailedFuture(Throwable cause) { - throw new NotImplementedException("Not implemented"); - } - - @Override - public ChannelPromise voidPromise() { - throw new NotImplementedException("Not implemented"); - } - - @Override - public Attribute attr(AttributeKey key) { - throw new NotImplementedException("Not implemented"); - } - - - @Override - public boolean hasAttr(AttributeKey attributeKey) { - return false; - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java b/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java deleted file mode 100644 index e21753dcd2..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/GrpcConverter.java +++ /dev/null @@ -1,733 +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.proxy.grpc.v2.common; -// -//import apache.rocketmq.v2.AckMessageRequest; -//import apache.rocketmq.v2.Broker; -//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -//import apache.rocketmq.v2.ClientType; -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Digest; -//import apache.rocketmq.v2.DigestType; -//import apache.rocketmq.v2.Encoding; -//import apache.rocketmq.v2.EndTransactionRequest; -//import apache.rocketmq.v2.FilterExpression; -//import apache.rocketmq.v2.FilterType; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -//import apache.rocketmq.v2.HeartbeatRequest; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.MessageQueue; -//import apache.rocketmq.v2.MessageType; -//import apache.rocketmq.v2.NotifyClientTerminationRequest; -//import apache.rocketmq.v2.Permission; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.SendMessageRequest; -//import apache.rocketmq.v2.Settings; -//import apache.rocketmq.v2.SubscriptionEntry; -//import apache.rocketmq.v2.SystemProperties; -//import apache.rocketmq.v2.TransactionResolution; -//import apache.rocketmq.v2.TransactionSource; -//import apache.rocketmq.v2.VerifyMessageResult; -//import com.google.common.collect.Maps; -//import com.google.protobuf.ByteString; -//import com.google.protobuf.Duration; -//import com.google.protobuf.Timestamp; -//import com.google.protobuf.util.Durations; -//import com.google.protobuf.util.Timestamps; -//import io.grpc.Context; -//import java.net.SocketAddress; -//import java.util.ArrayList; -//import java.util.Arrays; -//import java.util.HashMap; -//import java.util.HashSet; -//import java.util.List; -//import java.util.Map; -//import java.util.Set; -//import java.util.concurrent.TimeUnit; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.common.constant.ConsumeInitMode; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.constant.PermName; -//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.filter.ExpressionType; -//import org.apache.rocketmq.common.filter.FilterAPI; -//import org.apache.rocketmq.common.message.MessageAccessor; -//import org.apache.rocketmq.common.message.MessageConst; -//import org.apache.rocketmq.common.message.MessageDecoder; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.NamespaceUtil; -//import org.apache.rocketmq.common.protocol.body.CMResult; -//import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -//import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; -//import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -//import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -//import org.apache.rocketmq.common.protocol.route.QueueData; -//import org.apache.rocketmq.common.sysflag.MessageSysFlag; -//import org.apache.rocketmq.common.utils.BinaryUtil; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -//import org.apache.rocketmq.proxy.config.ConfigurationManager; -//import org.apache.rocketmq.proxy.service.transaction.TransactionId; -// -//public class GrpcConverter { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// public static String wrapResourceWithNamespace(Resource resource) { -// return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); -// } -// -// public static HeartbeatData buildHeartbeatData(String clientId, HeartbeatRequest request, -// Settings clientSettings) { -// HeartbeatData heartbeatData = new HeartbeatData(); -// heartbeatData.setClientID(clientId); -// switch (clientSettings.getClientType()) { -// case PRODUCER: { -// Set producerDataSet = new HashSet<>(); -// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { -// String topicName = wrapResourceWithNamespace(topic); -// producerDataSet.add(buildProducerData(topicName)); -// } -// heartbeatData.setProducerDataSet(producerDataSet); -// break; -// } -// case PUSH_CONSUMER: -// case SIMPLE_CONSUMER: { -// String groupName = wrapResourceWithNamespace(request.getGroup()); -// Set consumerDataSet = new HashSet<>(); -// consumerDataSet.add(buildConsumerData(groupName, clientSettings)); -// heartbeatData.setConsumerDataSet(consumerDataSet); -// break; -// } -// } -// return heartbeatData; -// } -// -// public static org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData(String groupName) { -// org.apache.rocketmq.common.protocol.heartbeat.ProducerData buildProducerData -// = new org.apache.rocketmq.common.protocol.heartbeat.ProducerData(); -// buildProducerData.setGroupName(groupName); -// return buildProducerData; -// } -// -// public static org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData(String groupName, -// Settings clientSettings) { -// org.apache.rocketmq.common.protocol.heartbeat.ConsumerData buildConsumerData = new org.apache.rocketmq.common.protocol.heartbeat.ConsumerData(); -// buildConsumerData.setGroupName(groupName); -// buildConsumerData.setConsumeType(buildConsumeType(clientSettings.getClientType())); -// -// buildConsumerData.setMessageModel(MessageModel.CLUSTERING); -// buildConsumerData.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET); -// Set subscriptionDataSet = -// buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()); -// buildConsumerData.setSubscriptionDataSet(subscriptionDataSet); -// return buildConsumerData; -// } -// -// public static ConsumeType buildConsumeType(ClientType clientType) { -// switch (clientType) { -// case SIMPLE_CONSUMER: -// return ConsumeType.CONSUME_ACTIVELY; -// case PUSH_CONSUMER: -// return ConsumeType.CONSUME_PASSIVELY; -// default: -// throw new IllegalArgumentException("Client type is not consumer, type: " + clientType); -// } -// } -// -// public static SendMessageRequestHeader buildSendMessageRequestHeader(SendMessageRequest request, -// String producerGroup, int queueId) { -// SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); -// -// if (request.getMessagesCount() <= 0) { -// throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); -// } -// if (request.getMessagesCount() > 1) { -// requestHeader.setBatch(true); -// } -// Message message = request.getMessages(0); -// SystemProperties systemProperties = message.getSystemProperties(); -// -// Map property = buildMessageProperty(message, producerGroup); -// requestHeader.setProducerGroup(producerGroup); -// requestHeader.setTopic(wrapResourceWithNamespace(message.getTopic())); -// requestHeader.setDefaultTopic(""); -// requestHeader.setDefaultTopicQueueNums(0); -// requestHeader.setQueueId(queueId); -// // sysFlag (body encoding & message type) -// int sysFlag = 0; -// Encoding bodyEncoding = systemProperties.getBodyEncoding(); -// if (bodyEncoding.equals(Encoding.GZIP)) { -// sysFlag |= MessageSysFlag.COMPRESSED_FLAG; -// } -// // transaction -// MessageType messageType = systemProperties.getMessageType(); -// if (messageType.equals(MessageType.TRANSACTION)) { -// sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; -// } -// requestHeader.setSysFlag(sysFlag); -// requestHeader.setBornTimestamp(Timestamps.toMillis(systemProperties.getBornTimestamp())); -// requestHeader.setFlag(0); -// requestHeader.setProperties(MessageDecoder.messageProperties2String(property)); -// requestHeader.setReconsumeTimes(systemProperties.getDeliveryAttempt()); -// -// return requestHeader; -// } -// -// public static PopMessageRequestHeader buildPopMessageRequestHeader(ReceiveMessageRequest request, long pollTime, boolean isFifo) { -// Resource group = request.getGroup(); -// String groupName = GrpcConverter.wrapResourceWithNamespace(group); -// MessageQueue messageQueue = request.getMessageQueue(); -// Resource topic = messageQueue.getTopic(); -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// int queueId = messageQueue.getId(); -// int maxMessageNumbers = request.getBatchSize(); -// if (maxMessageNumbers > ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) { -// log.warn("change maxNums from {} to {} for pop request, with info: topic:{}, group:{}", -// maxMessageNumbers, ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST, topicName, groupName); -// maxMessageNumbers = ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST; -// } -// long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); -// long bornTime = System.currentTimeMillis(); -// -// FilterExpression filterExpression = request.getFilterExpression(); -// String expression = filterExpression.getExpression(); -// String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); -// -// PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); -// requestHeader.setConsumerGroup(groupName); -// requestHeader.setTopic(topicName); -// requestHeader.setQueueId(queueId); -// requestHeader.setMaxMsgNums(maxMessageNumbers); -// requestHeader.setInvisibleTime(invisibleTime); -// requestHeader.setPollTime(pollTime); -// requestHeader.setBornTime(bornTime); -// requestHeader.setInitMode(ConsumeInitMode.MAX); -// requestHeader.setExpType(expressionType); -// requestHeader.setExp(expression); -// requestHeader.setOrder(isFifo); -// -// return requestHeader; -// } -// -// public static AckMessageRequestHeader buildAckMessageRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { -// return buildAckMessageRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle); -// } -// -// public static AckMessageRequestHeader buildAckMessageRequestHeader(AckMessageRequest request, ReceiptHandle handle) { -// return buildAckMessageRequestHeader(request.getTopic(), request.getGroup(), handle); -// } -// -// public static AckMessageRequestHeader buildAckMessageRequestHeader(Resource topic, Resource group, ReceiptHandle handle) { -// String groupName = GrpcConverter.wrapResourceWithNamespace(group); -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// -// AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); -// ackMessageRequestHeader.setConsumerGroup(groupName); -// ackMessageRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); -// ackMessageRequestHeader.setQueueId(handle.getQueueId()); -// ackMessageRequestHeader.setExtraInfo(handle.getReceiptHandle()); -// ackMessageRequestHeader.setOffset(handle.getOffset()); -// return ackMessageRequestHeader; -// } -// -// public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ChangeInvisibleDurationRequest request) { -// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); -// -// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); -// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); -// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); -// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); -// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); -// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); -// changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); -// return changeInvisibleTimeRequestHeader; -// } -// -// public static ChangeInvisibleTimeRequestHeader buildChangeInvisibleTimeRequestHeader(ReceiveMessageRequest request, ReceiptHandle handle) { -// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); -// -// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); -// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); -// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); -// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); -// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); -// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); -// changeInvisibleTimeRequestHeader.setInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); -// return changeInvisibleTimeRequestHeader; -// } -// -// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(ReceiveMessageRequest request, -// ReceiptHandle handle, String messageId, int maxReconsumeTimes) { -// return buildConsumerSendMsgBackRequestHeader(request.getMessageQueue().getTopic(), request.getGroup(), handle, messageId, maxReconsumeTimes); -// } -// -// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader( -// ForwardMessageToDeadLetterQueueRequest request) { -// ReceiptHandle handle = ReceiptHandle.decode(request.getReceiptHandle()); -// return buildConsumerSendMsgBackRequestHeader(request.getTopic(), request.getGroup(), handle, -// request.getMessageId(), request.getMaxDeliveryAttempts()); -// } -// -// public static ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Resource topic, Resource group, ReceiptHandle handle, -// String messageId, int maxReconsumeTimes) { -// String groupName = GrpcConverter.wrapResourceWithNamespace(group); -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// -// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); -// consumerSendMsgBackRequestHeader.setOffset(handle.getCommitLogOffset()); -// consumerSendMsgBackRequestHeader.setGroup(groupName); -// consumerSendMsgBackRequestHeader.setDelayLevel(-1); -// consumerSendMsgBackRequestHeader.setOriginMsgId(messageId); -// consumerSendMsgBackRequestHeader.setOriginTopic(handle.getRealTopic(topicName, groupName)); -// consumerSendMsgBackRequestHeader.setMaxReconsumeTimes(maxReconsumeTimes); -// return consumerSendMsgBackRequestHeader; -// } -// -// public static EndTransactionRequestHeader buildEndTransactionRequestHeader(EndTransactionRequest request, -// String producerGroup) { -// String messageId = request.getMessageId(); -// String transactionId = request.getTransactionId(); -// TransactionId handle; -// try { -// handle = TransactionId.decode(transactionId); -// } catch (Exception e) { -// throw new GrpcProxyException(Code.INVALID_TRANSACTION_ID, "Parse transaction id failed", e); -// } -// long transactionStateTableOffset = handle.getTranStateTableOffset(); -// long commitLogOffset = handle.getCommitLogOffset(); -// boolean fromTransactionCheck = request.getSource() == TransactionSource.SOURCE_SERVER_CHECK; -// int commitOrRollback = GrpcConverter.buildTransactionCommitOrRollback(request.getResolution()); -// -// EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); -// endTransactionRequestHeader.setProducerGroup(producerGroup); -// endTransactionRequestHeader.setMsgId(messageId); -// endTransactionRequestHeader.setTransactionId(handle.getBrokerTransactionId()); -// endTransactionRequestHeader.setTranStateTableOffset(transactionStateTableOffset); -// endTransactionRequestHeader.setCommitLogOffset(commitLogOffset); -// endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); -// endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); -// -// return endTransactionRequestHeader; -// } -// -// public static UnregisterClientRequestHeader buildUnregisterClientRequestHeader(String clientId, -// ClientType clientType, NotifyClientTerminationRequest request) { -// UnregisterClientRequestHeader header = new UnregisterClientRequestHeader(); -// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// header.setClientID(clientId); -// switch (clientType) { -// case PRODUCER: { -// header.setProducerGroup(groupName); -// break; -// } -// case PUSH_CONSUMER: -// case SIMPLE_CONSUMER: { -// header.setConsumerGroup(groupName); -// break; -// } -// } -// return header; -// } -// -// public static Map buildMessageProperty(Message message, String producerGroup) { -// org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); -// // set user properties -// Map userProperties = message.getUserPropertiesMap(); -// for (String key : userProperties.keySet()) { -// if (MessageConst.STRING_HASH_SET.contains(key)) { -// throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); -// } -// } -// MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); -// -// // set tag -// String tag = message.getSystemProperties().getTag(); -// if (!"".equals(tag)) { -// messageWithHeader.setTags(tag); -// } -// -// // set keys -// List keysList = message.getSystemProperties().getKeysList(); -// if (keysList.size() > 0) { -// messageWithHeader.setKeys(keysList); -// } -// -// // set message id -// String messageId = message.getSystemProperties().getMessageId(); -// if ("".equals(messageId)) { -// throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); -// } -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); -// -// // set transaction property -// MessageType messageType = message.getSystemProperties().getMessageType(); -// if (messageType.equals(MessageType.TRANSACTION)) { -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); -// -// Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); -// -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, -// String.valueOf(Durations.toSeconds(transactionResolveDelay))); -// } -// -// // set delay level or deliver timestamp -// if (message.getSystemProperties().hasDeliveryTimestamp()) { -// Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); -// String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); -// } -// -// // set reconsume times -// int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); -// MessageAccessor.setReconsumeTime(messageWithHeader, String.valueOf(reconsumeTimes)); -// // set producer group -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); -// // set message group -// String messageGroup = message.getSystemProperties().getMessageGroup(); -// if (!messageGroup.isEmpty()) { -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); -// } -// // set trace context -// String traceContext = message.getSystemProperties().getTraceContext(); -// if (!traceContext.isEmpty()) { -// MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); -// } -// return messageWithHeader.getProperties(); -// } -// -// public static List buildMessage(List protoMessageList, -// Resource topic) { -// String topicName = wrapResourceWithNamespace(topic); -// List messages = new ArrayList<>(); -// for (Message protoMessage : protoMessageList) { -// if (!protoMessage.getTopic().equals(topic)) { -// throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); -// } -// // here use topicName as producerGroup for transactional checker. -// messages.add(buildMessage(protoMessage, topicName)); -// } -// return messages; -// } -// -// public static org.apache.rocketmq.common.message.Message buildMessage(Message protoMessage, String producerGroup) { -// String topicName = wrapResourceWithNamespace(protoMessage.getTopic()); -// -// org.apache.rocketmq.common.message.Message message = -// new org.apache.rocketmq.common.message.Message(topicName, protoMessage.getBody().toByteArray()); -// Map messageProperty = buildMessageProperty(protoMessage, producerGroup); -// -// MessageAccessor.setProperties(message, messageProperty); -// return message; -// } -// -// public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { -// Broker broker = Broker.getDefaultInstance(); -// if (!StringUtils.isEmpty(brokerName)) { -// broker = Broker.newBuilder() -// .setName(brokerName) -// .setId(0) -// .build(); -// } -// return MessageQueue.newBuilder() -// .setId(messageExt.getQueueId()) -// .setTopic(Resource.newBuilder() -// .setName(NamespaceUtil.withoutNamespace(messageExt.getTopic())) -// .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(messageExt.getTopic())) -// .build()) -// .setBroker(broker) -// .build(); -// } -// -// public static String buildExpressionType(FilterType filterType) { -// switch (filterType) { -// case SQL: -// return ExpressionType.SQL92; -// case TAG: -// default: -// return ExpressionType.TAG; -// } -// } -// -// public static Set buildSubscriptionDataSet(List subscriptionEntryList) { -// Set subscriptionDataSet = new HashSet<>(); -// for (SubscriptionEntry sub : subscriptionEntryList) { -// String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); -// FilterExpression filterExpression = sub.getExpression(); -// subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); -// } -// return subscriptionDataSet; -// } -// -// public static SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { -// String expression = filterExpression.getExpression(); -// String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); -// try { -// return FilterAPI.build(topicName, expression, expressionType); -// } catch (Exception e) { -// throw new GrpcProxyException(Code.ILLEGAL_FILTER_EXPRESSION, "expression format is not correct", e); -// } -// } -// -// public static Message buildMessage(MessageExt messageExt) { -// Map userProperties = buildUserAttributes(messageExt); -// SystemProperties systemProperties = buildSystemProperties(messageExt); -// Resource topic = buildResource(messageExt.getTopic()); -// -// return Message.newBuilder() -// .setTopic(topic) -// .putAllUserProperties(userProperties) -// .setSystemProperties(systemProperties) -// .setBody(ByteString.copyFrom(messageExt.getBody())) -// .build(); -// } -// -// protected static Map buildUserAttributes(MessageExt messageExt) { -// Map userAttributes = new HashMap<>(); -// Map properties = messageExt.getProperties(); -// -// for (Map.Entry property : properties.entrySet()) { -// if (!MessageConst.STRING_HASH_SET.contains(property.getKey())) { -// userAttributes.put(property.getKey(), property.getValue()); -// } -// } -// -// return userAttributes; -// } -// -// protected static SystemProperties buildSystemProperties(MessageExt messageExt) { -// SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); -// -// // tag -// String tag = messageExt.getUserProperty(MessageConst.PROPERTY_TAGS); -// if (tag != null) { -// systemPropertiesBuilder.setTag(tag); -// } -// -// // keys -// String keys = messageExt.getKeys(); -// if (keys != null) { -// String[] keysArray = keys.split(MessageConst.KEY_SEPARATOR); -// systemPropertiesBuilder.addAllKeys(Arrays.asList(keysArray)); -// } -// -// // message_id -// String uniqKey = messageExt.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); -// if (uniqKey != null) { -// systemPropertiesBuilder.setMessageId(uniqKey); -// } -// -// // body_digest & body_encoding -// String md5Result = BinaryUtil.generateMd5(messageExt.getBody()); -// Digest digest = Digest.newBuilder() -// .setType(DigestType.MD5) -// .setChecksum(md5Result) -// .build(); -// systemPropertiesBuilder.setBodyDigest(digest); -// -// if ((messageExt.getSysFlag() & MessageSysFlag.COMPRESSED_FLAG) == MessageSysFlag.COMPRESSED_FLAG) { -// systemPropertiesBuilder.setBodyEncoding(Encoding.GZIP); -// } else { -// systemPropertiesBuilder.setBodyEncoding(Encoding.IDENTITY); -// } -// -// // message_type -// String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); -// String isTransValue = "true"; -// if (isTransValue.equals(isTrans)) { -// systemPropertiesBuilder.setMessageType(MessageType.TRANSACTION); -// } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null -// || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null -// || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { -// systemPropertiesBuilder.setMessageType(MessageType.DELAY); -// } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { -// systemPropertiesBuilder.setMessageType(MessageType.FIFO); -// } else { -// systemPropertiesBuilder.setMessageType(MessageType.NORMAL); -// } -// -// // born_timestamp (millis) -// long bornTimestamp = messageExt.getBornTimestamp(); -// systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); -// -// // born_host -// systemPropertiesBuilder.setBornHost(messageExt.getBornHostString()); -// -// // store_timestamp (millis) -// long storeTimestamp = messageExt.getStoreTimestamp(); -// systemPropertiesBuilder.setStoreTimestamp(Timestamps.fromMillis(storeTimestamp)); -// -// // store_host -// SocketAddress storeHost = messageExt.getStoreHost(); -// if (storeHost != null) { -// systemPropertiesBuilder.setStoreHost(storeHost.toString()); -// } -// -// // delivery_timestamp -// String deliverMsString; -// long deliverMs; -// if (messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { -// long delayMs = TimeUnit.SECONDS.toMillis(Long.parseLong(messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC))); -// deliverMs = System.currentTimeMillis() + delayMs; -// systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); -// } else { -// deliverMsString = messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS); -// if (deliverMsString != null) { -// deliverMs = Long.parseLong(deliverMsString); -// systemPropertiesBuilder.setDeliveryTimestamp(Timestamps.fromMillis(deliverMs)); -// } -// } -// -// // sharding key -// String shardingKey = messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY); -// if (shardingKey != null) { -// systemPropertiesBuilder.setMessageGroup(shardingKey); -// } -// -// // receipt_handle && invisible_period -// ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); -// if (receiptHandle != null) { -// systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); -// } -// -// // partition_id -// systemPropertiesBuilder.setQueueId(messageExt.getQueueId()); -// -// // partition_offset -// systemPropertiesBuilder.setQueueOffset(messageExt.getQueueOffset()); -// -// // delivery_attempt -// systemPropertiesBuilder.setDeliveryAttempt(messageExt.getReconsumeTimes() + 1); -// -// // trace context -// String traceContext = messageExt.getProperty(MessageConst.PROPERTY_TRACE_CONTEXT); -// if (traceContext != null) { -// systemPropertiesBuilder.setTraceContext(traceContext); -// } -// -// return systemPropertiesBuilder.build(); -// } -// -// public static int buildTransactionCommitOrRollback(TransactionResolution type) { -// switch (type) { -// case COMMIT: -// return MessageSysFlag.TRANSACTION_COMMIT_TYPE; -// case ROLLBACK: -// return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; -// default: -// return MessageSysFlag.TRANSACTION_NOT_TYPE; -// } -// } -// -// public static ConsumeMessageDirectlyResult buildConsumeMessageDirectlyResult(VerifyMessageResult request) { -// ConsumeMessageDirectlyResult consumeMessageDirectlyResult = new ConsumeMessageDirectlyResult(); -// switch (request.getStatus().getCode().getNumber()) { -// case Code.OK_VALUE: { -// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_SUCCESS); -// break; -// } -// case Code.FAILED_TO_CONSUME_MESSAGE_VALUE: { -// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_LATER); -// break; -// } -// case Code.MESSAGE_CORRUPTED_VALUE: { -// consumeMessageDirectlyResult.setConsumeResult(CMResult.CR_RETURN_NULL); -// break; -// } -// } -// consumeMessageDirectlyResult.setRemark("From gRPC client"); -// return consumeMessageDirectlyResult; -// } -// -// public static Resource buildResource(String resourceNameWithNamespace) { -// return Resource.newBuilder() -// .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) -// .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) -// .build(); -// } -// -// public static long buildPollTimeFromContext(Context ctx) { -// long timeRemaining = ctx.getDeadline() -// .timeRemaining(TimeUnit.MILLISECONDS); -// long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); -// if (pollTime <= 0) { -// pollTime = timeRemaining; -// } -// -// return pollTime; -// } -// -// public static List genMessageQueueFromQueueData(QueueData queueData, Resource topic, Broker broker) { -// List messageQueueList = new ArrayList<>(); -// -// int r = 0; -// int w = 0; -// int rw = 0; -// if (PermName.isWriteable(queueData.getPerm()) && PermName.isReadable(queueData.getPerm())) { -// rw = Math.min(queueData.getWriteQueueNums(), queueData.getReadQueueNums()); -// r = queueData.getReadQueueNums() - rw; -// w = queueData.getWriteQueueNums() - rw; -// } else if (PermName.isWriteable(queueData.getPerm())) { -// w = queueData.getWriteQueueNums(); -// } else if (PermName.isReadable(queueData.getPerm())) { -// r = queueData.getReadQueueNums(); -// } -// -// // r here means readOnly queue nums, w means writeOnly queue nums, while rw means both readable and writable queue nums. -// int queueIdIndex = 0; -// for (int i = 0; i < r; i++) { -// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) -// .setId(queueIdIndex++) -// .setPermission(Permission.READ) -// .build(); -// messageQueueList.add(messageQueue); -// } -// -// for (int i = 0; i < w; i++) { -// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) -// .setId(queueIdIndex++) -// .setPermission(Permission.WRITE) -// .build(); -// messageQueueList.add(messageQueue); -// } -// -// for (int i = 0; i < rw; i++) { -// MessageQueue messageQueue = MessageQueue.newBuilder().setBroker(broker).setTopic(topic) -// .setId(queueIdIndex++) -// .setPermission(Permission.READ_WRITE) -// .build(); -// messageQueueList.add(messageQueue); -// } -// -// return messageQueueList; -// } -// -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java deleted file mode 100644 index b6de2f47f5..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyException.java +++ /dev/null @@ -1,38 +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.proxy.grpc.v2.adapter; - -import apache.rocketmq.v2.Code; - -public class ProxyException extends RuntimeException { - - private final Code code; - - public ProxyException(Code code, String errorMessage) { - super(errorMessage); - this.code = code; - } - - public ProxyException(Code code, String message, Throwable cause) { - super(message, cause); - this.code = code; - } - - public Code getCode() { - return code; - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.java deleted file mode 100644 index 631bcaadca..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/ProxyMode.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.proxy.grpc.v2.adapter; - -public enum ProxyMode { - LOCAL("LOCAL"), - CLUSTER("CLUSTER"); - - private final String mode; - - ProxyMode(String mode) { - this.mode = mode; - } - - public static boolean isClusterMode(String mode) { - if (mode == null) { - return false; - } - return CLUSTER.mode.equals(mode.toUpperCase()); - } - - public static boolean isClusterMode(ProxyMode mode) { - if (mode == null) { - return false; - } - return CLUSTER.equals(mode); - } - - public static boolean isLocalMode(String mode) { - if (mode == null) { - return false; - } - return LOCAL.mode.equals(mode.toUpperCase()); - } - - public static boolean isLocalMode(ProxyMode mode) { - if (mode == null) { - return false; - } - return LOCAL.equals(mode); - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.java b/proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.java deleted file mode 100644 index 7f5ee2a13e..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/RequestMapping.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.proxy.grpc.v2.adapter; - -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.SendMessageRequest; -import java.util.HashMap; -import java.util.Map; -import org.apache.rocketmq.common.protocol.RequestCode; - -public class RequestMapping { - private final static Map REQUEST_MAP = new HashMap() { - { - // v2 - put(QueryRouteRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(HeartbeatRequest.getDescriptor().getFullName(), RequestCode.HEART_BEAT); - put(SendMessageRequest.getDescriptor().getFullName(), RequestCode.SEND_MESSAGE_V2); - put(QueryAssignmentRequest.getDescriptor().getFullName(), RequestCode.GET_ROUTEINFO_BY_TOPIC); - put(ReceiveMessageRequest.getDescriptor().getFullName(), RequestCode.PULL_MESSAGE); - put(AckMessageRequest.getDescriptor().getFullName(), RequestCode.UPDATE_CONSUMER_OFFSET); - put(ForwardMessageToDeadLetterQueueResponse.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - put(EndTransactionRequest.getDescriptor().getFullName(), RequestCode.END_TRANSACTION); - put(NotifyClientTerminationRequest.getDescriptor().getFullName(), RequestCode.UNREGISTER_CLIENT); - put(ChangeInvisibleDurationRequest.getDescriptor().getFullName(), RequestCode.CONSUMER_SEND_MSG_BACK); - } - }; - - public static int map(String rpcFullName) { - if (REQUEST_MAP.containsKey(rpcFullName)) { - return REQUEST_MAP.get(rpcFullName); - } - return RequestCode.HEART_BEAT; - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java b/proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java deleted file mode 100644 index d01abaf2ad..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/ResponseHook.java +++ /dev/null @@ -1,24 +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.proxy.grpc.v2.adapter; - -import org.apache.rocketmq.proxy.common.ProxyContext; - -public interface ResponseHook { - - void beforeResponse(ProxyContext ctx, T request, R response, Throwable t); -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java b/proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java deleted file mode 100644 index 3187df724c..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/channel/ReceiveMessageChannel.java +++ /dev/null @@ -1,31 +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.proxy.grpc.v2.adapter.channel; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import java.util.List; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; - -public class ReceiveMessageChannel extends InvocationChannel> { - public ReceiveMessageChannel(Context ctx, ReceiveMessageResponseHandler handler) { - super(ctx, handler); - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java b/proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java deleted file mode 100644 index a2b034529d..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/channel/SendMessageChannel.java +++ /dev/null @@ -1,30 +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.proxy.grpc.v2.adapter.channel; - -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import io.grpc.Context; -import org.apache.rocketmq.proxy.channel.InvocationChannel; -import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; - -public class SendMessageChannel extends InvocationChannel { - public SendMessageChannel(Context context, SendMessageResponseHandler handler) { - super(context, handler); - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java deleted file mode 100644 index ef867235cd..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ReceiveMessageResponseHandler.java +++ /dev/null @@ -1,146 +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.proxy.grpc.v2.adapter.handler; - -import apache.rocketmq.v2.ReceiveMessageRequest; -import com.google.common.base.Stopwatch; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; -import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode; - -public class ReceiveMessageResponseHandler implements ResponseHandler> { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final String brokerName; - private final boolean fifo; - - public ReceiveMessageResponseHandler(String brokerName, boolean fifo) { - this.brokerName = brokerName; - this.fifo = fifo; - } - - @Override - public void handle(RemotingCommand responseCommand, - InvocationContext> context) { - CompletableFuture> future = context.getResponse(); - - long currentTimeInMillis = System.currentTimeMillis(); - long popCosts = currentTimeInMillis - context.getTimestamp(); - try { - Stopwatch stopWatch = Stopwatch.createStarted(); - PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) responseCommand.readCustomHeader(); - List allMessageList = new ArrayList<>(); - - ReceiveMessageRequest request = context.getRequest(); - if (responseCommand.getCode() == RemotingSysResponseCode.SUCCESS) { - String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - ByteBuffer byteBuffer = ByteBuffer.wrap(responseCommand.getBody()); - List msgFoundList = MessageDecoder.decodes(byteBuffer); - - Map startOffsetInfo; - Map> msgOffsetInfo; - Map orderCountInfo; - startOffsetInfo = ExtraInfoUtil.parseStartOffsetInfo(responseHeader.getStartOffsetInfo()); - msgOffsetInfo = ExtraInfoUtil.parseMsgOffsetInfo(responseHeader.getMsgOffsetInfo()); - orderCountInfo = ExtraInfoUtil.parseOrderCountInfo(responseHeader.getOrderCountInfo()); - Map/*msg queueOffset*/> sortMap = new HashMap<>(16); - for (MessageExt messageExt : msgFoundList) { - String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); - if (!sortMap.containsKey(key)) { - sortMap.put(key, new ArrayList<>(4)); - } - sortMap.get(key).add(messageExt.getQueueOffset()); - } - Map map = new HashMap<>(5); - for (MessageExt messageExt : msgFoundList) { - if (startOffsetInfo == null) { - // we should set the check point info to extraInfo field , if the command is popMsg - // find pop ck offset - String key = messageExt.getTopic() + messageExt.getQueueId(); - if (!map.containsKey(messageExt.getTopic() + messageExt.getQueueId())) { - String extraInfo = ExtraInfoUtil.buildExtraInfo( - messageExt.getQueueOffset(), - responseHeader.getPopTime(), - responseHeader.getInvisibleTime(), - responseHeader.getReviveQid(), - messageExt.getTopic(), brokerName, - messageExt.getQueueId() - ); - map.put(key, extraInfo); - } - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, - map.get(key) + MessageConst.KEY_SEPARATOR + messageExt.getQueueOffset()); - } else { - String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), - messageExt.getQueueId()); - int index = sortMap.get(key).indexOf(messageExt.getQueueOffset()); - Long msgQueueOffset = msgOffsetInfo.get(key).get(index); - if (msgQueueOffset != messageExt.getQueueOffset()) { - log.warn("Queue offset[{}] of msg is strange, not equal to the stored in msg, {}", - msgQueueOffset, messageExt); - } - String extraInfo = ExtraInfoUtil.buildExtraInfo( - startOffsetInfo.get(key), - responseHeader.getPopTime(), - responseHeader.getInvisibleTime(), - responseHeader.getReviveQid(), - messageExt.getTopic(), - brokerName, - messageExt.getQueueId(), - msgQueueOffset - ); - messageExt.setQueueOffset(msgQueueOffset); - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, extraInfo); - if (fifo && orderCountInfo != null) { - Integer count = orderCountInfo.get(key); - if (count != null && count > 0) { - messageExt.setReconsumeTimes(count); - } - } - } - messageExt.setTopic(topicName); - messageExt.setBrokerName(brokerName); - messageExt.getProperties().computeIfAbsent(MessageConst.PROPERTY_FIRST_POP_TIME, - k -> String.valueOf(responseHeader.getPopTime())); - } - allMessageList.addAll(msgFoundList); - } - long elapsed = stopWatch.stop().elapsed(TimeUnit.MILLISECONDS); - log.debug("Translating remoting response to gRPC response costs {}ms. Duration request received: {}", elapsed, popCosts); - future.complete(allMessageList); - } catch (Exception e) { - log.error("Unexpected exception raised when handle pop remoting command", e); - future.completeExceptionally(e); - } - } -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java deleted file mode 100644 index 30bc3e3381..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/ResponseHandler.java +++ /dev/null @@ -1,25 +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.proxy.grpc.v2.adapter.handler; - -import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public interface ResponseHandler { - void handle(RemotingCommand responseCommand, InvocationContext context); -} diff --git a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java b/proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java deleted file mode 100644 index 9ce3ddcccc..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/adapter/handler/SendMessageResponseHandler.java +++ /dev/null @@ -1,84 +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.proxy.grpc.v2.adapter.handler; - -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.SendReceipt; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; -import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.channel.InvocationContext; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; - -public class SendMessageResponseHandler implements ResponseHandler { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final String messageId; - private final int sysFlag; - private final String localAddress; - - public SendMessageResponseHandler(String messageId, int sysFlag, String localAddress) { - this.messageId = messageId; - this.sysFlag = sysFlag; - this.localAddress = localAddress; - } - - @Override - public void handle(RemotingCommand responseCommand, - InvocationContext context) { - // If responseCommand equals to null, then the response has been written to channel. - // org.apache.rocketmq.broker.processor.SendMessageProcessor#handlePutMessageResult - // org.apache.rocketmq.broker.processor.AbstractSendMessageProcessor#doResponse - if (null != responseCommand) { - SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) responseCommand.readCustomHeader(); - int tranType = MessageSysFlag.getTransactionValue(sysFlag); - String transactionIdString = ""; - if (responseCommand.getCode() == ResponseCode.SUCCESS && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE) { - long commitLogOffset = 0L; - try { - commitLogOffset = TransactionId.generateCommitLogOffset(responseHeader.getMsgId()); - } catch (IllegalArgumentException e) { - log.warn("illegal messageId:{}", responseHeader.getMsgId()); - e.printStackTrace(); - } - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - RemotingUtil.string2SocketAddress(localAddress), - responseHeader.getTransactionId(), - commitLogOffset, - responseHeader.getQueueOffset() - ); - transactionIdString = transactionId.getProxyTransactionId(); - } - SendMessageResponse response = SendMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) - .addReceipts(SendReceipt.newBuilder() - .setMessageId(StringUtils.defaultString(messageId)) - .setTransactionId(StringUtils.defaultString(transactionIdString)) - .build()) - .build(); - context.getResponse().complete(response); - } - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java deleted file mode 100644 index 3807409816..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/AbstractRouteService.java +++ /dev/null @@ -1,99 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Endpoints; -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import apache.rocketmq.v2.QueryAssignmentResponse; -//import apache.rocketmq.v2.QueryRouteRequest; -//import apache.rocketmq.v2.QueryRouteResponse; -//import io.grpc.Context; -//import java.util.concurrent.CompletableFuture; -//import org.apache.rocketmq.proxy.common.ParameterConverter; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.AssignmentQueueSelector; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultAssignmentQueueSelector; -// -//public abstract class AbstractRouteService extends BaseService { -// protected volatile ParameterConverter queryRouteEndpointConverter; -// protected volatile ResponseHook queryRouteHook; -// -// protected volatile ParameterConverter queryAssignmentEndpointConverter; -// protected volatile ResponseHook queryAssignmentHook; -// protected volatile AssignmentQueueSelector assignmentQueueSelector; -// -// protected final GrpcClientManager grpcClientManager; -// -// public AbstractRouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { -// super(serviceManager); -// this.grpcClientManager = grpcClientManager; -// this.queryRouteEndpointConverter = (ctx, parameter) -> parameter; -// this.queryAssignmentEndpointConverter = (ctx, parameter) -> parameter; -// this.assignmentQueueSelector = new DefaultAssignmentQueueSelector(this.serviceManager.getTopicRouteService()); -// } -// -// public abstract CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); -// -// public abstract CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); -// -// public ParameterConverter getQueryRouteEndpointConverter() { -// return queryRouteEndpointConverter; -// } -// -// public void setQueryRouteEndpointConverter( -// ParameterConverter queryRouteEndpointConverter) { -// this.queryRouteEndpointConverter = queryRouteEndpointConverter; -// } -// -// public ResponseHook getQueryRouteHook() { -// return queryRouteHook; -// } -// -// public void setQueryRouteHook( -// ResponseHook queryRouteHook) { -// this.queryRouteHook = queryRouteHook; -// } -// -// public ParameterConverter getQueryAssignmentEndpointConverter() { -// return queryAssignmentEndpointConverter; -// } -// -// public void setQueryAssignmentEndpointConverter( -// ParameterConverter queryAssignmentEndpointConverter) { -// this.queryAssignmentEndpointConverter = queryAssignmentEndpointConverter; -// } -// -// public AssignmentQueueSelector getAssignmentQueueSelector() { -// return assignmentQueueSelector; -// } -// -// public void setAssignmentQueueSelector( -// AssignmentQueueSelector assignmentQueueSelector) { -// this.assignmentQueueSelector = assignmentQueueSelector; -// } -// -// public ResponseHook getQueryAssignmentHook() { -// return queryAssignmentHook; -// } -// -// public void setQueryAssignmentHook( -// ResponseHook queryAssignmentHook) { -// this.queryAssignmentHook = queryAssignmentHook; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 6a65830fca..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,122 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import java.util.Iterator; -//import java.util.List; -//import org.apache.rocketmq.client.consumer.PopStatus; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; -// -//public abstract class BaseReceiveMessageResponseStreamWriter { -// -// protected final StreamObserver streamObserver; -// protected final ResponseHook receiveMessageHook; -// protected final ReceiveMessageResultFilter receiveMessageResultFilter; -// -// public interface Builder { -// BaseReceiveMessageResponseStreamWriter build( -// StreamObserver observer, -// ResponseHook hook); -// } -// -// public BaseReceiveMessageResponseStreamWriter( -// StreamObserver observer, -// ResponseHook hook, -// ReceiveMessageResultFilter messageResultFilter) { -// streamObserver = observer; -// receiveMessageHook = hook; -// receiveMessageResultFilter = messageResultFilter; -// } -// -// public void write(Context ctx, ReceiveMessageRequest request, PopStatus status, List messageFoundList) { -// ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( -// ctx, -// request, -// receiveMessageHook, -// streamObserver); -// try { -// switch (status) { -// case FOUND: -// List messageList = this.receiveMessageResultFilter.filterMessage(ctx, request, messageFoundList); -// if (messageList.isEmpty()) { -// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) -// .build()); -// } else { -// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build()); -// Iterator messageIterator = messageList.iterator(); -// while (messageIterator.hasNext()) { -// Message curMessage = messageIterator.next(); -// try { -// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() -// .setMessage(curMessage) -// .build()); -// } catch (Throwable t) { -// this.processThrowableWhenWriteMessage(t, ctx, request, curMessage); -// messageIterator.forEachRemaining(message -> -// this.processThrowableWhenWriteMessage(t, ctx, request, message)); -// return; -// } -// } -// } -// break; -// case POLLING_FULL: -// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) -// .build()); -// break; -// case NO_NEW_MSG: -// case POLLING_NOT_FOUND: -// default: -// responseStreamObserver.onNext(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")) -// .build()); -// break; -// } -// } catch (Throwable t) { -// write(ctx, request, t); -// } finally { -// responseStreamObserver.onCompleted(); -// } -// } -// -// protected abstract void processThrowableWhenWriteMessage(Throwable throwable, -// Context context, ReceiveMessageRequest request, Message message); -// -// public void write(Context ctx, ReceiveMessageRequest request, Throwable throwable) { -// ReceiveMessageResponseStreamObserver responseStreamObserver = new ReceiveMessageResponseStreamObserver( -// ctx, -// request, -// receiveMessageHook, -// streamObserver); -// ResponseWriter.write( -// responseStreamObserver, -// ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() -// ); -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java deleted file mode 100644 index cf40b63772..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/BaseReceiveMessageResultFilter.java +++ /dev/null @@ -1,67 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.Settings; -//import io.grpc.Context; -//import java.util.ArrayList; -//import java.util.Collections; -//import java.util.List; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -//import org.apache.rocketmq.proxy.common.utils.FilterUtils; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -// -//public abstract class BaseReceiveMessageResultFilter implements ReceiveMessageResultFilter { -// -// protected final GrpcClientManager grpcClientManager; -// -// public BaseReceiveMessageResultFilter(GrpcClientManager manager) { -// grpcClientManager = manager; -// } -// -// @Override -// public List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList) { -// if (messageExtList == null || messageExtList.isEmpty()) { -// return Collections.emptyList(); -// } -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); -// SubscriptionData subscriptionData = GrpcConverter.buildSubscriptionData(topicName, request.getFilterExpression()); -// Settings settings = grpcClientManager.getClientSettings(ctx); -// int maxAttempts = settings.getBackoffPolicy().getMaxAttempts(); -// List resMessageList = new ArrayList<>(); -// for (MessageExt messageExt : messageExtList) { -// if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { -// processNoMatchMessage(ctx, request, messageExt); -// continue; -// } -// if (messageExt.getReconsumeTimes() >= maxAttempts) { -// processExceedMaxAttemptsMessage(ctx, request, messageExt, maxAttempts); -// continue; -// } -// resMessageList.add(GrpcConverter.buildMessage(messageExt)); -// } -// return resMessageList; -// } -// -// protected abstract void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt); -// -// protected abstract void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, int maxAttempts); -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java b/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java deleted file mode 100644 index a1e2a904d3..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/BaseService.java +++ /dev/null @@ -1,77 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.FilterExpression; -//import apache.rocketmq.v2.Resource; -//import io.grpc.Context; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.proxy.common.StartAndShutdown; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -// -//public abstract class BaseService implements StartAndShutdown { -// -// protected final ServiceManager serviceManager; -// -// public BaseService(ServiceManager serviceManager) { -// this.serviceManager = serviceManager; -// } -// -// public static ReceiptHandle resolveReceiptHandle(Context ctx, String receiptHandleStr) { -// ReceiptHandle receiptHandle = ReceiptHandle.decode(receiptHandleStr); -// if (receiptHandle.isExpired()) { -// throw new ProxyException(Code.RECEIPT_HANDLE_EXPIRED, "handle has expired"); -// } -// return receiptHandle; -// } -// -// public static String getBrokerAddr(Context ctx, TopicRouteService topicRouteService, String brokerName) throws Exception { -// if (StringUtils.isBlank(brokerName)) { -// throw new ProxyException(Code.UNRECOGNIZED, "broker name is empty"); -// } -// String addr = topicRouteService.getBrokerAddr(brokerName); -// if (StringUtils.isBlank(addr)) { -// throw new ProxyException(Code.UNRECOGNIZED, brokerName + " not exist"); -// } -// return addr; -// } -// -// protected String getBrokerAddr(Context ctx, String brokerName) throws Exception { -// return getBrokerAddr(ctx, this.serviceManager.getTopicRouteService(), brokerName); -// } -// -// protected void checkSubscriptionData(Resource topic, FilterExpression filterExpression) { -// // for checking filterExpression. -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// GrpcConverter.buildSubscriptionData(topicName, filterExpression); -// } -// -// @Override -// public void start() throws Exception { -// -// } -// -// @Override -// public void shutdown() throws Exception { -// -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java b/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java deleted file mode 100644 index 966e4e3570..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/ClientSettingsService.java +++ /dev/null @@ -1,65 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.Settings; -//import apache.rocketmq.v2.TelemetryCommand; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -// -//public class ClientSettingsService { -// -// private final ChannelManager channelManager; -// private final GrpcClientManager grpcClientManager; -// private final TelemetryCommandManager telemetryCommandManager; -// -// public ClientSettingsService(ChannelManager channelManager, -// GrpcClientManager grpcClientManager, -// TelemetryCommandManager telemetryCommandManager) { -// this.channelManager = channelManager; -// this.grpcClientManager = grpcClientManager; -// this.telemetryCommandManager = telemetryCommandManager; -// } -// -// public TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// grpcClientManager.updateClientSettings(clientId, request.getSettings()); -// Settings settings = grpcClientManager.getClientSettings(clientId); -// if (settings.hasPublishing()) { -// for (Resource topic : settings.getPublishing().getTopicsList()) { -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// GrpcClientChannel producerChannel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); -// producerChannel.setClientObserver(responseObserver); -// } -// } -// if (settings.hasSubscription()) { -// String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); -// GrpcClientChannel consumerChannel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); -// consumerChannel.setClientObserver(responseObserver); -// } -// return TelemetryCommand.newBuilder() -// .setSettings(settings) -// .build(); -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java b/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java deleted file mode 100644 index 0c223d86bb..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/ClusterGrpcActivity.java +++ /dev/null @@ -1,184 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.AckMessageRequest; -//import apache.rocketmq.v2.AckMessageResponse; -//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -//import apache.rocketmq.v2.EndTransactionRequest; -//import apache.rocketmq.v2.EndTransactionResponse; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -//import apache.rocketmq.v2.HeartbeatRequest; -//import apache.rocketmq.v2.HeartbeatResponse; -//import apache.rocketmq.v2.NotifyClientTerminationRequest; -//import apache.rocketmq.v2.NotifyClientTerminationResponse; -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import apache.rocketmq.v2.QueryAssignmentResponse; -//import apache.rocketmq.v2.QueryRouteRequest; -//import apache.rocketmq.v2.QueryRouteResponse; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import apache.rocketmq.v2.SendMessageRequest; -//import apache.rocketmq.v2.SendMessageResponse; -//import apache.rocketmq.v2.TelemetryCommand; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.Executors; -//import java.util.concurrent.ScheduledExecutorService; -//import org.apache.rocketmq.common.ThreadFactoryImpl; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -//import org.apache.rocketmq.proxy.common.StartAndShutdown; -//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; -//import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ConsumerService; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ForwardClientService; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.ProducerService; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.RouteService; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.TransactionService; -//import org.apache.rocketmq.proxy.grpc2.v2.GrpcMessingActivity; -// -//public class ClusterGrpcActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// protected final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( -// new ThreadFactoryImpl("ClusterGrpcServiceScheduledThread") -// ); -// -// protected ChannelManager channelManager; -// protected ServiceManager serviceManager; -// protected ProducerService producerService; -// protected ConsumerService consumerService; -// protected RouteService routeService; -// protected ForwardClientService clientService; -// protected TransactionService transactionService; -// protected TelemetryCommandManager pollCommandResponseManager; -// protected GrpcClientManager grpcClientManager; -// -// public ClusterGrpcActivity() { -// this.init(); -// } -// -// protected void init() { -// this.channelManager = new ChannelManager(); -// this.grpcClientManager = new GrpcClientManager(); -// this.pollCommandResponseManager = new TelemetryCommandManager(); -// this.serviceManager = new ServiceManager(new GrpcTransactionStateChecker()); -// this.consumerService = new ConsumerService(serviceManager, grpcClientManager); -// this.producerService = new ProducerService(serviceManager); -// this.routeService = new RouteService(serviceManager, grpcClientManager); -// this.clientService = new ForwardClientService(serviceManager, scheduledExecutorService, -// channelManager, grpcClientManager, pollCommandResponseManager); -// this.transactionService = new TransactionService(serviceManager, channelManager); -// -// this.appendStartAndShutdown(new ClusterGrpcServiceStartAndShutdown()); -// this.appendStartAndShutdown(this.serviceManager); -// this.appendStartAndShutdown(this.consumerService); -// this.appendStartAndShutdown(this.producerService); -// this.appendStartAndShutdown(this.routeService); -// this.appendStartAndShutdown(this.clientService); -// this.appendStartAndShutdown(this.transactionService); -// } -// -// @Override -// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { -// return routeService.queryRoute(ctx, request); -// } -// -// @Override -// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { -// return clientService.heartbeat(ctx, request); -// } -// -// @Override -// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { -// return producerService.sendMessage(ctx, request); -// } -// -// @Override -// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { -// return routeService.queryAssignment(ctx, request); -// } -// -// @Override -// public void receiveMessage(Context ctx, ReceiveMessageRequest request, -// StreamObserver responseObserver) { -// consumerService.receiveMessage(ctx, request, responseObserver); -// } -// -// @Override -// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { -// return consumerService.ackMessage(ctx, request); -// } -// -// @Override -// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, -// ForwardMessageToDeadLetterQueueRequest request) { -// return producerService.forwardMessageToDeadLetterQueue(ctx, request); -// } -// -// @Override -// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { -// return transactionService.endTransaction(ctx, request); -// } -// -// @Override -// public CompletableFuture notifyClientTermination(Context ctx, -// NotifyClientTerminationRequest request) { -// return clientService.notifyClientTermination(ctx, request); -// } -// -// @Override -// public CompletableFuture changeInvisibleDuration(Context ctx, -// ChangeInvisibleDurationRequest request) { -// return consumerService.changeInvisibleDuration(ctx, request); -// } -// -// @Override -// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { -// return clientService.telemetry(ctx, responseObserver); -// } -// -// protected class ClusterGrpcServiceStartAndShutdown implements StartAndShutdown { -// -// @Override -// public void start() throws Exception { -// } -// -// @Override -// public void shutdown() throws Exception { -// scheduledExecutorService.shutdown(); -// } -// } -// -// protected class GrpcTransactionStateChecker implements TransactionStateChecker { -// -// @Override -// public void checkTransactionState(TransactionStateCheckRequest checkData) { -// transactionService.checkTransactionState(checkData); -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java b/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java deleted file mode 100644 index daa2977ab6..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/LocalGrpcActivity.java +++ /dev/null @@ -1,566 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.AckMessageEntry; -//import apache.rocketmq.v2.AckMessageRequest; -//import apache.rocketmq.v2.AckMessageResponse; -//import apache.rocketmq.v2.AckMessageResultEntry; -//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.EndTransactionRequest; -//import apache.rocketmq.v2.EndTransactionResponse; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -//import apache.rocketmq.v2.HeartbeatRequest; -//import apache.rocketmq.v2.HeartbeatResponse; -//import apache.rocketmq.v2.NotifyClientTerminationRequest; -//import apache.rocketmq.v2.NotifyClientTerminationResponse; -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import apache.rocketmq.v2.QueryAssignmentResponse; -//import apache.rocketmq.v2.QueryRouteRequest; -//import apache.rocketmq.v2.QueryRouteResponse; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.SendMessageRequest; -//import apache.rocketmq.v2.SendMessageResponse; -//import apache.rocketmq.v2.Settings; -//import apache.rocketmq.v2.TelemetryCommand; -//import apache.rocketmq.v2.ThreadStackTrace; -//import apache.rocketmq.v2.VerifyMessageResult; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import io.netty.channel.Channel; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import org.apache.rocketmq.broker.BrokerController; -//import org.apache.rocketmq.broker.client.ClientChannelInfo; -//import org.apache.rocketmq.broker.client.ConsumerGroupEvent; -//import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; -//import org.apache.rocketmq.broker.client.ProducerChangeListener; -//import org.apache.rocketmq.broker.client.ProducerGroupEvent; -//import org.apache.rocketmq.client.consumer.PopStatus; -//import org.apache.rocketmq.common.MQVersion; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.message.MessageBatch; -//import org.apache.rocketmq.common.message.MessageClientIDSetter; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.message.MessageQueue; -//import org.apache.rocketmq.common.protocol.RequestCode; -//import org.apache.rocketmq.common.protocol.ResponseCode; -//import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; -//import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; -//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader; -//import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.channel.InvocationContext; -//import org.apache.rocketmq.proxy.channel.SimpleChannel; -//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -//import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; -//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -//import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.ReceiveMessageChannel; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.SendMessageChannel; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.ReceiveMessageResponseHandler; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.handler.SendMessageResponseHandler; -//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResponseStreamWriter; -//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalReceiveMessageResultFilter; -//import org.apache.rocketmq.proxy.grpc.v2.service.local.LocalWriteQueueSelector; -//import org.apache.rocketmq.proxy.grpc.v2.service.local.RouteService; -//import org.apache.rocketmq.proxy.grpc2.v2.GrpcMessingActivity; -//import org.apache.rocketmq.remoting.RemotingServer; -//import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; -//import org.apache.rocketmq.remoting.protocol.LanguageCode; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -// -//public class LocalGrpcActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// private final BrokerController brokerController; -// private final ChannelManager channelManager; -// private final TelemetryCommandManager telemetryCommandManager; -// private final GrpcClientManager grpcClientManager; -// private final RouteService routeService; -// private final ClientSettingsService clientSettingsService; -// private final LocalWriteQueueSelector localWriteQueueSelector; -// private final BaseReceiveMessageResponseStreamWriter.Builder streamWriterBuilder; -// -// private volatile ResponseHook receiveMessageHook; -// -// public LocalGrpcActivity(BrokerController brokerController) { -// this(brokerController, new TelemetryCommandManager()); -// } -// -// /** -// * For unit test -// * @param brokerController BrokerController works in local mode -// * @param telemetryCommandManager Used to manage telemetry command -// */ -// LocalGrpcActivity(BrokerController brokerController, TelemetryCommandManager telemetryCommandManager) { -// this.brokerController = brokerController; -// this.channelManager = new ChannelManager(); -// // TransactionStateChecker is not used in Local mode. -// ServiceManager serviceManager = new ServiceManager(null); -// this.telemetryCommandManager = telemetryCommandManager; -// this.grpcClientManager = new GrpcClientManager(); -// this.routeService = new RouteService(serviceManager, grpcClientManager); -// this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); -// this.localWriteQueueSelector = new LocalWriteQueueSelector(brokerController.getBrokerConfig().getBrokerName(), -// brokerController.getTopicConfigManager(), serviceManager.getTopicRouteService()); -// -// this.brokerController.getConsumerManager().appendConsumerIdsChangeListener(new ConsumerIdsChangeListenerImpl()); -// this.brokerController.getProducerManager().appendProducerChangeListener(new ProducerChangeListenerImpl()); -// -// this.streamWriterBuilder = (observer, hook) -> new LocalReceiveMessageResponseStreamWriter( -// observer, -// hook, -// channelManager, -// brokerController, -// new LocalReceiveMessageResultFilter(channelManager, brokerController, grpcClientManager) -// ); -// -// this.appendStartAndShutdown(serviceManager); -// } -// -// @Override -// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { -// return this.routeService.queryRoute(ctx, request); -// } -// -// @Override -// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { -// LanguageCode languageCode; -// String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// languageCode = LanguageCode.valueOf(language); -// -// Settings clientSettings = grpcClientManager.getClientSettings(clientId); -// HeartbeatData heartbeatData = GrpcConverter.buildHeartbeatData(clientId, request, clientSettings); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); -// command.setLanguage(languageCode); -// command.setVersion(MQVersion.Version.V5_0_0.ordinal()); -// command.setBody(heartbeatData.encode()); -// command.makeCustomHeaderToNet(); -// -// CompletableFuture future = new CompletableFuture<>(); -// switch (clientSettings.getClientType()) { -// case PRODUCER: { -// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); -// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); -// -// this.brokerController.getClientManageProcessor() -// .heartBeat(simpleChannelHandlerContext, command); -// } -// HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, "Producer heartbeat")) -// .build(); -// future.complete(heartbeatResponse); -// break; -// } -// case PUSH_CONSUMER: -// case SIMPLE_CONSUMER: { -// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, groupName, clientId, telemetryCommandManager); -// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); -// -// RemotingCommand response = this.brokerController.getClientManageProcessor() -// .heartBeat(simpleChannelHandlerContext, command); -// HeartbeatResponse heartbeatResponse = HeartbeatResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) -// .build(); -// future.complete(heartbeatResponse); -// break; -// } -// default: { -// throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); -// } -// } -// -// return future; -// } -// -// @Override -// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { -// MessageQueue messageQueue = localWriteQueueSelector.selectQueue(ctx, request).getMessageQueue(); -// String topicName = messageQueue.getTopic(); -// SendMessageRequestHeader requestHeader = GrpcConverter.buildSendMessageRequestHeader(request, topicName, messageQueue.getQueueId()); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); -// List messageList = GrpcConverter.buildMessage(request.getMessagesList(), request.getMessages(0).getTopic()); -// String messageId; -// if (messageList.size() == 1) { -// org.apache.rocketmq.common.message.Message message = messageList.get(0); -// command.setBody(message.getBody()); -// messageId = MessageClientIDSetter.getUniqID(message); -// } else { -// MessageBatch messageBatch = MessageBatch.generateFromList(messageList); -// MessageClientIDSetter.setUniqID(messageBatch); -// messageBatch.setBody(messageBatch.encode()); -// command.setBody(messageBatch.encode()); -// messageId = MessageClientIDSetter.getUniqID(messageBatch); -// } -// command.makeCustomHeaderToNet(); -// -// SendMessageResponseHandler handler = new SendMessageResponseHandler(messageId, requestHeader.getSysFlag(), brokerController.getBrokerAddr()); -// SendMessageChannel channel = channelManager.createChannel(ctx, context -> new SendMessageChannel(context, handler), SendMessageChannel.class); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// CompletableFuture future = new CompletableFuture<>(); -// InvocationContext context -// = new InvocationContext<>(request, future); -// channel.registerInvocationContext(command.getOpaque(), context); -// try { -// RemotingCommand response = brokerController.getSendMessageProcessor() -// .processRequest(channelHandlerContext, command); -// if (response != null) { -// handler.handle(response, context); -// channel.eraseInvocationContext(command.getOpaque()); -// } -// } catch (final Exception e) { -// log.error("Failed to process send message command", e); -// channel.eraseInvocationContext(command.getOpaque()); -// future.completeExceptionally(e); -// } -// return future; -// } -// -// @Override -// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { -// return this.routeService.queryAssignment(ctx, request); -// } -// -// @Override -// public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { -// long pollTime = GrpcConverter.buildPollTimeFromContext(ctx); -// // TODO: get fifo config from subscriptionGroupManager -// boolean fifo = false; -// BaseReceiveMessageResponseStreamWriter writer = streamWriterBuilder.build(responseObserver, receiveMessageHook); -// ReceiveMessageResponseHandler handler = new ReceiveMessageResponseHandler(brokerController.getBrokerConfig().getBrokerName(), fifo); -// ReceiveMessageChannel channel = channelManager.createChannel(ctx, context -> new ReceiveMessageChannel(context, handler), ReceiveMessageChannel.class); -// CompletableFuture> future = new CompletableFuture<>(); -// InvocationContext> context -// = new InvocationContext<>(request, future); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// PopMessageRequestHeader requestHeader = GrpcConverter.buildPopMessageRequestHeader(request, pollTime, fifo); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); -// command.makeCustomHeaderToNet(); -// channel.registerInvocationContext(command.getOpaque(), context); -// try { -// RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(channelHandlerContext, command); -// if (response != null) { -// handler.handle(response, context); -// channel.eraseInvocationContext(command.getOpaque()); -// } -// } catch (Exception e) { -// log.error("Failed to process pop message command", e); -// channel.eraseInvocationContext(command.getOpaque()); -// future.completeExceptionally(e); -// } -// future.thenAccept(r -> writer.write(ctx, request, PopStatus.FOUND, r)) -// .exceptionally(e -> { -// writer.write(ctx, request, e); -// return null; -// }); -// } -// -// @Override -// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// CompletableFuture future = new CompletableFuture<>(); -// List ackMessageResultEntryList = new ArrayList<>(); -// for (AckMessageEntry entry : request.getEntriesList()) { -// ReceiptHandle receiptHandle = ReceiptHandle.decode(entry.getReceiptHandle()); -// if (receiptHandle.isExpired()) { -// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() -// .setReceiptHandle(entry.getReceiptHandle()) -// .setMessageId(entry.getMessageId()) -// .setStatus(ResponseBuilder.buildStatus(Code.RECEIPT_HANDLE_EXPIRED, "expired")) -// .build()); -// continue; -// } -// AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, receiptHandle); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); -// command.makeCustomHeaderToNet(); -// -// try { -// RemotingCommand responseCommand = brokerController.getAckMessageProcessor() -// .processRequest(channelHandlerContext, command); -// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() -// .setReceiptHandle(entry.getReceiptHandle()) -// .setMessageId(entry.getMessageId()) -// .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())) -// .build()); -// } catch (Exception e) { -// log.error("Exception raised when ack message", e); -// ackMessageResultEntryList.add(AckMessageResultEntry.newBuilder() -// .setReceiptHandle(entry.getReceiptHandle()) -// .setMessageId(entry.getMessageId()) -// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, e.getMessage())) -// .build()); -// } -// } -// AckMessageResponse response = AckMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(ResponseCode.SUCCESS, "ok")) -// .addAllEntries(ackMessageResultEntryList) -// .build(); -// future.complete(response); -// return future; -// } -// -// @Override -// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, -// ForwardMessageToDeadLetterQueueRequest request) { -// SimpleChannel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// -// ConsumerSendMsgBackRequestHeader requestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); -// command.makeCustomHeaderToNet(); -// -// CompletableFuture future = new CompletableFuture<>(); -// try { -// RemotingCommand response = brokerController.getSendMessageProcessor() -// .processRequest(channelHandlerContext, command); -// -// future.complete(ForwardMessageToDeadLetterQueueResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(response.getCode(), response.getRemark())) -// .build()); -// } catch (Exception e) { -// log.error("Exception raised when forwardMessageToDeadLetterQueue", e); -// future.completeExceptionally(e); -// } -// return future; -// } -// -// @Override -// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// EndTransactionRequestHeader requestHeader = GrpcConverter.buildEndTransactionRequestHeader(request, topicName); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); -// command.makeCustomHeaderToNet(); -// -// CompletableFuture future = new CompletableFuture<>(); -// try { -// RemotingCommand responseCommand = brokerController.getEndTransactionProcessor() -// .processRequest(channelHandlerContext, command); -// EndTransactionResponse.Builder builder = EndTransactionResponse.newBuilder(); -// if (null != responseCommand) { -// builder.setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); -// } else { -// builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "Response command is null")); -// } -// EndTransactionResponse response = builder.build(); -// future.complete(response); -// } catch (Exception e) { -// log.error("Exception raised while endTransaction", e); -// future.completeExceptionally(e); -// } -// return future; -// } -// -// public void reportThreadStackTrace(Context ctx, ThreadStackTrace request) { -// String nonce = request.getNonce(); -// String threadStack = request.getThreadStackTrace(); -// TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); -// if (pollCommandResponseFuture != null) { -// Integer opaque = pollCommandResponseFuture.getOpaque(); -// if (opaque != null) { -// RemotingServer remotingServer = this.brokerController.getRemotingServer(); -// if (remotingServer instanceof NettyRemotingAbstract) { -// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); -// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); -// ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); -// runningInfo.setJstack(threadStack); -// remotingCommand.setBody(runningInfo.encode()); -// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); -// } -// } -// } -// } -// -// public void reportVerifyMessageResult(Context ctx, VerifyMessageResult request) { -// String nonce = request.getNonce(); -// TelemetryCommandRecord pollCommandResponseFuture = telemetryCommandManager.getCommand(nonce); -// if (pollCommandResponseFuture != null) { -// Integer opaque = pollCommandResponseFuture.getOpaque(); -// if (opaque != null) { -// RemotingServer remotingServer = this.brokerController.getRemotingServer(); -// if (remotingServer instanceof NettyRemotingAbstract) { -// NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "From gRPC client"); -// remotingCommand.setOpaque(pollCommandResponseFuture.getOpaque()); -// ConsumeMessageDirectlyResult result = GrpcConverter.buildConsumeMessageDirectlyResult(request); -// remotingCommand.setBody(result.encode()); -// nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(channelManager.createChannel(ctx)), remotingCommand); -// } -// } -// } -// } -// -// @Override -// public CompletableFuture notifyClientTermination(Context ctx, -// NotifyClientTerminationRequest request) { -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// Settings clientSettings = grpcClientManager.getClientSettings(clientId); -// UnregisterClientRequestHeader header = GrpcConverter.buildUnregisterClientRequestHeader(clientId, clientSettings.getClientType(), request); -// -// RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, header); -// remotingCommand.makeCustomHeaderToNet(); -// try { -// this.brokerController.getClientManageProcessor().unregisterClient(simpleChannelHandlerContext, remotingCommand); -// } catch (Exception ignored) { -// } -// return new CompletableFuture<>(); -// } -// -// @Override -// public CompletableFuture changeInvisibleDuration(Context ctx, -// ChangeInvisibleDurationRequest request) { -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext channelHandlerContext = new SimpleChannelHandlerContext(channel); -// -// ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); -// ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); -// command.makeCustomHeaderToNet(); -// -// CompletableFuture future = new CompletableFuture<>(); -// try { -// RemotingCommand responseCommand = brokerController.getChangeInvisibleTimeProcessor() -// .processRequest(channelHandlerContext, command); -// ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) responseCommand.readCustomHeader(); -// ChangeInvisibleDurationResponse.Builder builder = ChangeInvisibleDurationResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(responseCommand.getCode(), responseCommand.getRemark())); -// if (responseCommand.getCode() == ResponseCode.SUCCESS) { -// builder.setReceiptHandle(ReceiptHandle.builder() -// .startOffset(requestHeader.getOffset()) -// .retrieveTime(responseHeader.getPopTime()) -// .invisibleTime(responseHeader.getInvisibleTime()) -// .reviveQueueId(responseHeader.getReviveQid()) -// .topicType(receiptHandle.getTopicType()) -// .brokerName(brokerController.getBrokerConfig().getBrokerName()) -// .queueId(requestHeader.getQueueId()) -// .offset(requestHeader.getOffset()) -// .build() -// .encode()); -// } -// -// future.complete(builder.build()); -// } catch (Exception e) { -// log.error("Exception raised while changeInvisibleDuration", e); -// future.completeExceptionally(e); -// } -// return future; -// } -// -// @Override -// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// return new StreamObserver() { -// @Override -// public void onNext(TelemetryCommand request) { -// switch (request.getCommandCase()) { -// case SETTINGS: { -// responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); -// break; -// } -// case THREAD_STACK_TRACE: { -// reportThreadStackTrace(ctx, request.getThreadStackTrace()); -// break; -// } -// case VERIFY_MESSAGE_RESULT: { -// reportVerifyMessageResult(ctx, request.getVerifyMessageResult()); -// break; -// } -// default: { -// throw new IllegalArgumentException("Request type is illegal"); -// } -// } -// } -// -// @Override -// public void onError(Throwable t) { -// -// } -// -// @Override -// public void onCompleted() { -// responseObserver.onCompleted(); -// } -// }; -// } -// -// protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { -// -// @Override -// public void handle(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]; -// channelManager.onClientOffline(clientChannelInfo.getClientId()); -// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); -// } -// } -// } -// -// @Override -// public void shutdown() { -// -// } -// } -// -// protected class ProducerChangeListenerImpl implements ProducerChangeListener { -// -// @Override -// public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { -// if (event == ProducerGroupEvent.CLIENT_UNREGISTER) { -// channelManager.onClientOffline(clientChannelInfo.getClientId()); -// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); -// } -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java deleted file mode 100644 index 2f36081448..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResponseStreamObserver.java +++ /dev/null @@ -1,67 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.stub.StreamObserver; -//import org.apache.rocketmq.proxy.common.ProxyContext; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseWriter; -// -//public class ReceiveMessageResponseStreamObserver implements StreamObserver { -// -// private final ProxyContext context; -// private final ReceiveMessageRequest request; -// private final ResponseHook receiveMessageHook; -// private final StreamObserver observer; -// -// public ReceiveMessageResponseStreamObserver(ProxyContext context, ReceiveMessageRequest request, -// ResponseHook receiveMessageHook, -// StreamObserver observer) { -// this.context = context; -// this.request = request; -// this.receiveMessageHook = receiveMessageHook; -// this.observer = observer; -// } -// -// @Override -// public void onNext(ReceiveMessageResponse response) { -// if (receiveMessageHook != null) { -// receiveMessageHook.beforeResponse(context, request, response, null); -// } -// observer.onNext(response); -// } -// -// @Override -// public void onError(Throwable throwable) { -// if (receiveMessageHook != null) { -// receiveMessageHook.beforeResponse(context, request, null, throwable); -// } -// observer.onError(throwable); -// } -// -// @Override -// public void onCompleted() { -// observer.onCompleted(); -// } -// -// public boolean isCancelled() { -// return ResponseWriter.isCancelled(observer); -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java deleted file mode 100644 index f837861968..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/ReceiveMessageResultFilter.java +++ /dev/null @@ -1,29 +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.proxy.grpc.v2.service; -// -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import io.grpc.Context; -//import java.util.List; -//import org.apache.rocketmq.common.message.MessageExt; -// -//public interface ReceiveMessageResultFilter { -// -// List filterMessage(Context ctx, ReceiveMessageRequest request, List messageExtList); -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java deleted file mode 100644 index d065a9cf1d..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/AssignmentQueueSelector.java +++ /dev/null @@ -1,27 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import io.grpc.Context; -//import java.util.List; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -// -//public interface AssignmentQueueSelector { -// -// List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception; -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java deleted file mode 100644 index 2db4f9b1b7..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ConsumerService.java +++ /dev/null @@ -1,283 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.AckMessageEntry; -//import apache.rocketmq.v2.AckMessageRequest; -//import apache.rocketmq.v2.AckMessageResponse; -//import apache.rocketmq.v2.AckMessageResultEntry; -//import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -//import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import org.apache.rocketmq.client.consumer.AckResult; -//import org.apache.rocketmq.client.consumer.AckStatus; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.ForwardProducer; -//import org.apache.rocketmq.proxy.service.ForwardReadConsumer; -//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; -// -//public class ConsumerService extends BaseService { -// protected final ForwardReadConsumer readConsumer; -// protected final ForwardWriteConsumer writeConsumer; -// /** -// * For sending messages back to broker. -// */ -// protected final ForwardProducer producer; -// protected final GrpcClientManager grpcClientManager; -// -// private volatile ReadQueueSelector readQueueSelector; -// private volatile BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder; -// -// private volatile ResponseHook receiveMessageHook; -// private volatile ResponseHook ackMessageHook; -// private volatile ResponseHook changeInvisibleDurationHook; -// -// public ConsumerService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { -// super(serviceManager); -// this.readConsumer = serviceManager.getForwardReadConsumer(); -// this.writeConsumer = serviceManager.getForwardWriteConsumer(); -// this.producer = serviceManager.getForwardProducer(); -// this.grpcClientManager = grpcClientManager; -// -// this.readQueueSelector = new DefaultReadQueueSelector(serviceManager.getTopicRouteService()); -// this.receiveMessageWriterBuilder = (observer, hook) -> new DefaultReceiveMessageResponseStreamWriter( -// observer, -// hook, -// writeConsumer, -// serviceManager.getTopicRouteService(), -// new DefaultReceiveMessageResultFilter( -// producer, writeConsumer, grpcClientManager, serviceManager.getTopicRouteService()) -// ); -// } -// -// public void receiveMessage(Context ctx, ReceiveMessageRequest request, -// StreamObserver responseObserver) { -// BaseReceiveMessageResponseStreamWriter writer = receiveMessageWriterBuilder.build(responseObserver, receiveMessageHook); -// try { -// PopMessageRequestHeader requestHeader = this.buildPopMessageRequestHeader(ctx, request); -// SelectableMessageQueue messageQueue = this.readQueueSelector.select(ctx, request, requestHeader); -// -// if (messageQueue == null) { -// throw new ProxyException(Code.FORBIDDEN, "no readable topic route for topic " + requestHeader.getTopic()); -// } -// -// this.readConsumer.popMessage( -// ctx, -// messageQueue.getBrokerAddr(), -// messageQueue.getBrokerName(), -// requestHeader, -// requestHeader.getPollTime()) -// .thenAccept(result -> writer.write(ctx, request, result.getPopStatus(), result.getMsgFoundList())) -// .exceptionally(e -> { -// writer.write(ctx, request, e); -// return null; -// }); -// } catch (Throwable t) { -// writer.write(ctx, request, t); -// } -// } -// -// protected PopMessageRequestHeader buildPopMessageRequestHeader(Context ctx, ReceiveMessageRequest request) { -// checkSubscriptionData(request.getMessageQueue().getTopic(), request.getFilterExpression()); -// boolean fifo = grpcClientManager.getClientSettings(ctx).getSubscription().getFifo(); -// return GrpcConverter.buildPopMessageRequestHeader(request, GrpcConverter.buildPollTimeFromContext(ctx), fifo); -// } -// -// public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (ackMessageHook != null) { -// ackMessageHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; -// for (int i = 0; i < request.getEntriesCount(); i++) { -// futures[i] = processAckMessage(ctx, request, request.getEntries(i)); -// } -// CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { -// if (throwable != null) { -// future.completeExceptionally(throwable); -// return; -// } -// List entryList = new ArrayList<>(); -// for (CompletableFuture entryFuture : futures) { -// entryFuture.thenAccept(entryList::add); -// } -// AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .addAllEntries(entryList); -// future.complete(responseBuilder.build()); -// }); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -// -// protected CompletableFuture processAckMessage(Context ctx, AckMessageRequest request, -// AckMessageEntry ackMessageEntry) { -// CompletableFuture future = new CompletableFuture<>(); -// AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) -// .setMessageId(ackMessageEntry.getMessageId()) -// .setReceiptHandle(ackMessageEntry.getReceiptHandle()); -// -// try { -// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, ackMessageEntry.getReceiptHandle()); -// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); -// -// AckMessageRequestHeader requestHeader = this.buildAckMessageRequestHeader(ctx, request, receiptHandle); -// CompletableFuture ackResultFuture = this.writeConsumer.ackMessage(ctx, brokerAddr, ackMessageEntry.getMessageId(), requestHeader); -// ackResultFuture -// .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) -// .exceptionally(throwable -> { -// future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); -// return null; -// }); -// } catch (Throwable t) { -// future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); -// } -// return future; -// } -// -// protected AckMessageRequestHeader buildAckMessageRequestHeader(Context ctx, AckMessageRequest request, -// ReceiptHandle handle) { -// return GrpcConverter.buildAckMessageRequestHeader(request, handle); -// } -// -// protected AckMessageResultEntry convertToAckMessageResultEntry(Context ctx, AckMessageEntry ackMessageEntry, -// AckResult ackResult) { -// if (AckStatus.OK.equals(ackResult.getStatus())) { -// return AckMessageResultEntry.newBuilder() -// .setMessageId(ackMessageEntry.getMessageId()) -// .setReceiptHandle(ackMessageEntry.getReceiptHandle()) -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build(); -// } -// return AckMessageResultEntry.newBuilder() -// .setMessageId(ackMessageEntry.getMessageId()) -// .setReceiptHandle(ackMessageEntry.getReceiptHandle()) -// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) -// .build(); -// } -// -// public CompletableFuture changeInvisibleDuration(Context ctx, -// ChangeInvisibleDurationRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// -// try { -// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); -// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); -// -// ChangeInvisibleTimeRequestHeader requestHeader = convertToChangeInvisibleTimeRequestHeader(ctx, request); -// future = this.writeConsumer.changeInvisibleTimeAsync(ctx, brokerAddr, receiptHandle.getBrokerName(), -// request.getMessageId(), requestHeader) -// .thenApply(result -> convertToChangeInvisibleDurationResponse(ctx, request, result)); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// future.whenComplete((response, throwable) -> { -// if (changeInvisibleDurationHook != null) { -// changeInvisibleDurationHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// return future; -// } -// -// protected ChangeInvisibleTimeRequestHeader convertToChangeInvisibleTimeRequestHeader(Context ctx, -// ChangeInvisibleDurationRequest request) { -// return GrpcConverter.buildChangeInvisibleTimeRequestHeader(request); -// } -// -// protected ChangeInvisibleDurationResponse convertToChangeInvisibleDurationResponse(Context ctx, -// ChangeInvisibleDurationRequest request, AckResult ackResult) { -// if (AckStatus.OK.equals(ackResult.getStatus())) { -// return ChangeInvisibleDurationResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .setReceiptHandle(ackResult.getExtraInfo()) -// .build(); -// } -// return ChangeInvisibleDurationResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) -// .build(); -// } -// -// public ReadQueueSelector getReadQueueSelector() { -// return readQueueSelector; -// } -// -// public void setReadQueueSelector(ReadQueueSelector readQueueSelector) { -// this.readQueueSelector = readQueueSelector; -// } -// -// public BaseReceiveMessageResponseStreamWriter.Builder getReceiveMessageWriterBuilder() { -// return receiveMessageWriterBuilder; -// } -// -// public void setReceiveMessageWriterBuilder( -// BaseReceiveMessageResponseStreamWriter.Builder receiveMessageWriterBuilder) { -// this.receiveMessageWriterBuilder = receiveMessageWriterBuilder; -// } -// -// public ResponseHook getReceiveMessageHook() { -// return receiveMessageHook; -// } -// -// public void setReceiveMessageHook( -// ResponseHook receiveMessageHook) { -// this.receiveMessageHook = receiveMessageHook; -// } -// -// public ResponseHook getAckMessageHook() { -// return ackMessageHook; -// } -// -// public void setAckMessageHook( -// ResponseHook ackMessageHook) { -// this.ackMessageHook = ackMessageHook; -// } -// -// public ResponseHook getChangeInvisibleDurationHook() { -// return changeInvisibleDurationHook; -// } -// -// public void setChangeInvisibleDurationHook( -// ResponseHook changeInvisibleDurationHook) { -// this.changeInvisibleDurationHook = changeInvisibleDurationHook; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java deleted file mode 100644 index 87bc8cc0ad..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultAssignmentQueueSelector.java +++ /dev/null @@ -1,41 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import io.grpc.Context; -//import java.util.List; -//import org.apache.rocketmq.proxy.service.route.MessageQueueView; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -// -//public class DefaultAssignmentQueueSelector implements AssignmentQueueSelector { -// -// private final TopicRouteService topicRouteService; -// -// public DefaultAssignmentQueueSelector(TopicRouteService topicRouteService) { -// this.topicRouteService = topicRouteService; -// } -// -// @Override -// public List getAssignment(Context ctx, QueryAssignmentRequest request) throws Exception { -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// MessageQueueView messageQueueView = topicRouteService.getAllMessageQueueView(topicName); -// return messageQueueView.getReadSelector().getBrokerActingQueues(); -// } -//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java deleted file mode 100644 index ecc4b2988c..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReadQueueSelector.java +++ /dev/null @@ -1,55 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import io.grpc.Context; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -// -//public class DefaultReadQueueSelector implements ReadQueueSelector { -// -// private final TopicRouteService topicRouteService; -// -// public DefaultReadQueueSelector(TopicRouteService topicRouteService) { -// this.topicRouteService = topicRouteService; -// } -// -// @Override -// public SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader) { -// SelectableMessageQueue messageQueue = null; -// try { -// String topic = requestHeader.getTopic(); -// -// if (request.hasMessageQueue() && request.getMessageQueue().hasBroker()) { -// String brokerName = request.getMessageQueue().getBroker().getName(); -// if (StringUtils.isNotBlank(brokerName)) { -// messageQueue = topicRouteService.selectReadBrokerByName(topic, brokerName); -// } -// } -// -// if (messageQueue == null) { -// messageQueue = topicRouteService.selectOneReadBroker(topic, null); -// } -// return messageQueue; -// } catch (Throwable t) { -// return null; -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 09c57539ba..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,96 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import java.time.Duration; -//import org.apache.rocketmq.client.consumer.AckStatus; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; -//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -// -//public class DefaultReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { -// protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); -// protected final ForwardWriteConsumer writeConsumer; -// protected final TopicRouteService topicRouteService; -// -// public DefaultReceiveMessageResponseStreamWriter( -// StreamObserver observer, -// ResponseHook hook, -// ForwardWriteConsumer writeConsumer, -// TopicRouteService topicRouteService, -// ReceiveMessageResultFilter receiveMessageResultFilter) { -// super(observer, hook, receiveMessageResultFilter); -// this.writeConsumer = writeConsumer; -// this.topicRouteService = topicRouteService; -// } -// -// @Override -// protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, -// Message message) { -// this.nackFailToWriteMessage(context, request, message); -// } -// -// protected void nackFailToWriteMessage(Context ctx, ReceiveMessageRequest request, Message message) { -// try { -// String receiptHandleStr = message.getSystemProperties().getReceiptHandle(); -// ReceiptHandle handle = BaseService.resolveReceiptHandle(ctx, receiptHandleStr); -// String brokerAddr = BaseService.getBrokerAddr(ctx, this.topicRouteService, handle.getBrokerName()); -// -// String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); -// ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); -// changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); -// changeInvisibleTimeRequestHeader.setTopic(handle.getRealTopic(topicName, groupName)); -// changeInvisibleTimeRequestHeader.setQueueId(handle.getQueueId()); -// changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); -// changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); -// changeInvisibleTimeRequestHeader.setInvisibleTime(NACK_INVISIBLE_TIME); -// -// this.writeConsumer.changeInvisibleTimeAsync( -// ctx, -// brokerAddr, -// handle.getBrokerName(), -// message.getSystemProperties().getMessageId(), -// changeInvisibleTimeRequestHeader -// ).whenComplete((ackResult, t) -> { -// if (t != null) { -// log.warn("err when nack message. request:{}, message:{}", request, message, t); -// } else if (!AckStatus.OK.equals(ackResult.getStatus())) { -// log.warn("nack failed. request:{}, message:{}, ackResult:{}", request, message, ackResult); -// } -// }); -// } catch (Throwable t) { -// log.warn("err when nack message. request:{}, message:{}", request, message, t); -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java deleted file mode 100644 index 15c8bfe864..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultReceiveMessageResultFilter.java +++ /dev/null @@ -1,127 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import io.grpc.Context; -//import java.util.concurrent.CompletableFuture; -//import org.apache.rocketmq.client.consumer.AckResult; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -//import org.apache.rocketmq.proxy.service.ForwardProducer; -//import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -// -//import static org.apache.rocketmq.proxy.grpc.v2.service.BaseService.getBrokerAddr; -// -//public class DefaultReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { -// -// protected final ForwardProducer producer; -// protected final ForwardWriteConsumer writeConsumer; -// protected final TopicRouteService topicRouteService; -// -// private volatile ResponseHook ackNoMatchedMessageHook; -// private volatile ResponseHook forwardToDLQInRecvMessageHook; -// -// public DefaultReceiveMessageResultFilter(ForwardProducer producer, ForwardWriteConsumer writeConsumer, -// GrpcClientManager grpcClientManager, TopicRouteService topicRouteService) { -// super(grpcClientManager); -// this.producer = producer; -// this.writeConsumer = writeConsumer; -// this.topicRouteService = topicRouteService; -// } -// -// @Override -// protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { -// CompletableFuture future = new CompletableFuture<>(); -// -// ReceiptHandle handle = ReceiptHandle.create(messageExt); -// if (handle == null) { -// return; -// } -// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); -// try { -// String brokerAddr = getBrokerAddr(ctx, topicRouteService, handle.getBrokerName()); -// future = this.writeConsumer.ackMessage(ctx, brokerAddr, messageExt.getMsgId(), ackMessageRequestHeader); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// -// future.whenComplete((ackResult, throwable) -> { -// if (ackNoMatchedMessageHook != null) { -// ackNoMatchedMessageHook.beforeResponse(ctx, ackMessageRequestHeader, ackResult, throwable); -// } -// }); -// } -// -// @Override -// protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, -// int maxAttempts) { -// CompletableFuture future = new CompletableFuture<>(); -// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = new ConsumerSendMsgBackRequestHeader(); -// -// try { -// ReceiptHandle handle = ReceiptHandle.create(messageExt); -// if (handle == null) { -// return; -// } -// String brokerAddr = getBrokerAddr(ctx, topicRouteService, handle.getBrokerName()); -// ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader( -// request, -// handle, -// messageExt.getMsgId(), -// maxAttempts); -// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); -// -// future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// -// future.whenComplete((result, throwable) -> { -// if (forwardToDLQInRecvMessageHook != null) { -// forwardToDLQInRecvMessageHook.beforeResponse(ctx, consumerSendMsgBackRequestHeader, result, throwable); -// } -// }); -// } -// -// public ResponseHook getAckNoMatchedMessageHook() { -// return ackNoMatchedMessageHook; -// } -// -// public void setAckNoMatchedMessageHook( -// ResponseHook ackNoMatchedMessageHook) { -// this.ackNoMatchedMessageHook = ackNoMatchedMessageHook; -// } -// -// public ResponseHook getForwardToDLQInRecvMessageHook() { -// return forwardToDLQInRecvMessageHook; -// } -// -// public void setForwardToDLQInRecvMessageHook( -// ResponseHook forwardToDLQInRecvMessageHook) { -// this.forwardToDLQInRecvMessageHook = forwardToDLQInRecvMessageHook; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java deleted file mode 100644 index ab48b6fdac..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/DefaultWriteQueueSelector.java +++ /dev/null @@ -1,77 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.SendMessageRequest; -//import io.grpc.Context; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -// -//public class DefaultWriteQueueSelector implements WriteQueueSelector { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// protected final TopicRouteService topicRouteService; -// -// public DefaultWriteQueueSelector(TopicRouteService topicRouteService) { -// this.topicRouteService = topicRouteService; -// } -// -// @Override -// public SelectableMessageQueue selectQueue( -// Context ctx, -// SendMessageRequest request -// ) { -// try { -// if (request.getMessagesCount() <= 0) { -// throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); -// } -// Message message = request.getMessages(0); -// String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); -// String shardingKey = null; -// if (request.getMessagesCount() == 1) { -// shardingKey = message.getSystemProperties().getMessageGroup(); -// } -// SelectableMessageQueue targetMessageQueue; -// if (StringUtils.isNotEmpty(shardingKey)) { -// // With shardingKey -// targetMessageQueue = selectOrderQueue(topic, shardingKey); -// } else { -// targetMessageQueue = selectNormalQueue(topic); -// } -// return targetMessageQueue; -// } catch (Exception e) { -// log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); -// return null; -// } -// } -// -// protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { -// return this.topicRouteService.selectOneWriteQueue(topic, null); -// } -// -// protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { -// return this.topicRouteService.selectOneWriteQueueByKey(topic, shardingKey); -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java deleted file mode 100644 index d5dcbbdd75..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ForwardClientService.java +++ /dev/null @@ -1,266 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.HeartbeatRequest; -//import apache.rocketmq.v2.HeartbeatResponse; -//import apache.rocketmq.v2.NotifyClientTerminationRequest; -//import apache.rocketmq.v2.NotifyClientTerminationResponse; -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.Settings; -//import apache.rocketmq.v2.TelemetryCommand; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import java.time.Duration; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.ScheduledExecutorService; -//import java.util.concurrent.TimeUnit; -//import org.apache.rocketmq.broker.client.ClientChannelInfo; -//import org.apache.rocketmq.broker.client.ConsumerGroupEvent; -//import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; -//import org.apache.rocketmq.broker.client.ConsumerManager; -//import org.apache.rocketmq.broker.client.ProducerChangeListener; -//import org.apache.rocketmq.broker.client.ProducerGroupEvent; -//import org.apache.rocketmq.broker.client.ProducerManager; -//import org.apache.rocketmq.common.MQVersion; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -//import org.apache.rocketmq.proxy.grpc.v2.service.ClientSettingsService; -//import org.apache.rocketmq.remoting.protocol.LanguageCode; -// -//public class ForwardClientService extends BaseService { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// protected final ChannelManager channelManager; -// protected final GrpcClientManager grpcClientManager; -// protected final TelemetryCommandManager telemetryCommandManager; -// -// protected ConsumerManager consumerManager; -// protected ProducerManager producerManager; -// protected ClientSettingsService clientSettingsService; -// -// public ForwardClientService( -// ServiceManager serviceManager, -// ScheduledExecutorService scheduledExecutorService, -// ChannelManager channelManager, -// GrpcClientManager grpcClientManager, -// TelemetryCommandManager telemetryCommandManager -// ) { -// super(serviceManager); -// scheduledExecutorService.scheduleWithFixedDelay( -// this::scanNotActiveChannel, -// Duration.ofSeconds(10).toMillis(), -// Duration.ofSeconds(10).toMillis(), -// TimeUnit.MILLISECONDS); -// this.channelManager = channelManager; -// this.grpcClientManager = grpcClientManager; -// this.telemetryCommandManager = telemetryCommandManager; -// -// this.clientSettingsService = new ClientSettingsService(this.channelManager, this.grpcClientManager, this.telemetryCommandManager); -// this.consumerManager = new ConsumerManager(new ConsumerIdsChangeListenerImpl()); -// this.producerManager = new ProducerManager(); -// this.producerManager.appendProducerChangeListener(new ProducerChangeListenerImpl()); -// } -// -// protected class ConsumerIdsChangeListenerImpl implements ConsumerIdsChangeListener { -// -// @Override -// public void handle(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]; -// channelManager.onClientOffline(clientChannelInfo.getClientId()); -// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); -// } -// } -// } -// -// @Override -// public void shutdown() { -// -// } -// } -// -// protected class ProducerChangeListenerImpl implements ProducerChangeListener { -// -// @Override -// public void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo) { -// switch (event) { -// case GROUP_UNREGISTER: -// serviceManager.getTransactionHeartbeatRegisterService().onProducerGroupOffline(group); -// break; -// case CLIENT_UNREGISTER: -// channelManager.onClientOffline(clientChannelInfo.getClientId()); -// grpcClientManager.removeClientSettings(clientChannelInfo.getClientId()); -// break; -// default: -// break; -// } -// } -// } -// -// public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// -// try { -// String language = InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE); -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// LanguageCode languageCode = LanguageCode.valueOf(language); -// -// Settings clientSettings = grpcClientManager.getClientSettings(clientId); -// switch (clientSettings.getClientType()) { -// case PRODUCER: { -// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// GrpcClientChannel channel = GrpcClientChannel.create(channelManager, topicName, clientId, telemetryCommandManager); -// ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); -// // use topic name as producer group -// producerManager.registerProducer(topicName, clientChannelInfo); -// serviceManager.getTransactionHeartbeatRegisterService().addProducerGroup(topicName, topicName); -// } -// break; -// } -// case PUSH_CONSUMER: -// case SIMPLE_CONSUMER: { -// if (!request.hasGroup()) { -// throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); -// } -// String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// GrpcClientChannel channel = GrpcClientChannel.create(ctx, channelManager, consumerGroup, clientId, telemetryCommandManager); -// ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); -// -// consumerManager.registerConsumer( -// consumerGroup, -// clientChannelInfo, -// GrpcConverter.buildConsumeType(clientSettings.getClientType()), -// MessageModel.CLUSTERING, -// ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, -// GrpcConverter.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()), -// false -// ); -// break; -// } -// default: { -// throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); -// } -// } -// future.complete(HeartbeatResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build()); -// return future; -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -// -// public CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// -// try { -// String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); -// Settings clientSettings = grpcClientManager.getClientSettings(clientId); -// -// switch (clientSettings.getClientType()) { -// case PRODUCER: -// for (Resource topic : clientSettings.getPublishing().getTopicsList()) { -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// // user topic name as producer group -// GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, topicName, clientId); -// if (channel != null) { -// producerManager.doChannelCloseEvent(topicName, channel); -// } -// } -// break; -// case PUSH_CONSUMER: -// case SIMPLE_CONSUMER: -// if (!request.hasGroup()) { -// throw new ProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); -// } -// String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); -// GrpcClientChannel channel = GrpcClientChannel.removeChannel(channelManager, consumerGroup, clientId); -// if (channel != null) { -// consumerManager.doChannelCloseEvent(consumerGroup, channel); -// } -// break; -// default: -// break; -// } -// future.complete(NotifyClientTerminationResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build()); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -// -// public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { -// return new StreamObserver() { -// @Override -// public void onNext(TelemetryCommand request) { -// if (request.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) { -// responseObserver.onNext(clientSettingsService.processClientSettings(ctx, request, responseObserver)); -// } -// } -// -// @Override -// public void onError(Throwable t) { -// -// } -// -// @Override -// public void onCompleted() { -// responseObserver.onCompleted(); -// } -// }; -// } -// -// private void scanNotActiveChannel() { -// try { -// this.consumerManager.scanNotActiveChannel(); -// this.producerManager.scanNotActiveChannel(); -// } catch (Exception e) { -// log.error("error occurred when scan not active client channels.", e); -// } -// } -// -// public ConsumerManager getConsumerManager() { -// return consumerManager; -// } -// -// public ProducerManager getProducerManager() { -// return producerManager; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java deleted file mode 100644 index a6d851bb10..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ProducerService.java +++ /dev/null @@ -1,184 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -//import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.SendMessageRequest; -//import apache.rocketmq.v2.SendMessageResponse; -//import apache.rocketmq.v2.SendReceipt; -//import com.beust.jcommander.internal.Lists; -//import io.grpc.Context; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.client.producer.SendResult; -//import org.apache.rocketmq.client.producer.SendStatus; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -//import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.ForwardProducer; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -// -//public class ProducerService extends BaseService { -// -// protected final ForwardProducer producer; -// private volatile WriteQueueSelector writeQueueSelector; -// private volatile ResponseHook sendMessageHook; -// private volatile ResponseHook forwardMessageToDLQHook; -// -// public ProducerService(ServiceManager serviceManager) { -// super(serviceManager); -// this.producer = serviceManager.getForwardProducer(); -// -// this.writeQueueSelector = new DefaultWriteQueueSelector(this.serviceManager.getTopicRouteService()); -// } -// -// public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// -// try { -// SelectableMessageQueue selectableMessageQueue = writeQueueSelector.selectQueue(ctx, request); -// if (selectableMessageQueue == null) { -// throw new ProxyException(Code.FORBIDDEN, "no writeable topic route"); -// } -// -// // send message to broker. -// future = this.producer.sendMessage( -// ctx, -// selectableMessageQueue.getBrokerAddr(), -// selectableMessageQueue.getBrokerName(), -// convertToMessageList(ctx, request), -// convertToSendMessageRequestHeader(ctx, request, selectableMessageQueue) -// ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// -// future.whenComplete((response, throwable) -> { -// if (sendMessageHook != null) { -// sendMessageHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// return future; -// } -// -// protected SendMessageRequestHeader convertToSendMessageRequestHeader(Context ctx, SendMessageRequest request, SelectableMessageQueue selectableMessageQueue) { -// // use topic name as group -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getMessages(0).getTopic()); -// return GrpcConverter.buildSendMessageRequestHeader(request, topicName, -// selectableMessageQueue.getQueueId()); -// } -// -// protected List convertToMessageList(Context ctx, SendMessageRequest request) { -// // use topic name as group -// Resource topic = request.getMessages(0).getTopic(); -// String topicName = GrpcConverter.wrapResourceWithNamespace(topic); -// return GrpcConverter.buildMessage(request.getMessagesList(), topic); -// } -// -// protected SendMessageResponse convertToSendMessageResponse(Context ctx, SendMessageRequest request, -// SendResult result) { -// if (result.getSendStatus() != SendStatus.SEND_OK) { -// return SendMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) -// .build(); -// } -// -// List sendReceiptList = Lists.newArrayList(); -// sendReceiptList.add(SendReceipt.newBuilder() -// .setMessageId(StringUtils.defaultString(result.getMsgId())) -// .setTransactionId(StringUtils.defaultString(result.getTransactionId())) -// .build()); -// return SendMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .addAllReceipts(sendReceiptList) -// .build(); -// } -// -// public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, -// ForwardMessageToDeadLetterQueueRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// -// try { -// ReceiptHandle receiptHandle = resolveReceiptHandle(ctx, request.getReceiptHandle()); -// String brokerAddr = this.getBrokerAddr(ctx, receiptHandle.getBrokerName()); -// ConsumerSendMsgBackRequestHeader sendMsgBackRequestHeader = this.buildConsumerSendMsgBackRequestHeader(ctx, request); -// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader( -// request.getTopic(), request.getGroup(), receiptHandle); -// -// future = this.producer.sendMessageBackThenAckOrg(ctx, brokerAddr, sendMsgBackRequestHeader, ackMessageRequestHeader) -// .thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// future.whenComplete((response, throwable) -> { -// if (forwardMessageToDLQHook != null) { -// forwardMessageToDLQHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// return future; -// } -// -// protected ConsumerSendMsgBackRequestHeader buildConsumerSendMsgBackRequestHeader(Context ctx, -// ForwardMessageToDeadLetterQueueRequest request) { -// return GrpcConverter.buildConsumerSendMsgBackRequestHeader(request); -// } -// -// protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, -// RemotingCommand result) { -// return ForwardMessageToDeadLetterQueueResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) -// .build(); -// } -// -// public WriteQueueSelector getWriteQueueSelector() { -// return writeQueueSelector; -// } -// -// public void setWriteQueueSelector(WriteQueueSelector writeQueueSelector) { -// this.writeQueueSelector = writeQueueSelector; -// } -// -// public ResponseHook getSendMessageHook() { -// return sendMessageHook; -// } -// -// public void setSendMessageHook( -// ResponseHook sendMessageHook) { -// this.sendMessageHook = sendMessageHook; -// } -// -// public ResponseHook getForwardMessageToDLQHook() { -// return forwardMessageToDLQHook; -// } -// -// public void setForwardMessageToDLQHook( -// ResponseHook forwardMessageToDLQHook) { -// this.forwardMessageToDLQHook = forwardMessageToDLQHook; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java deleted file mode 100644 index ea0e078b84..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/ReadQueueSelector.java +++ /dev/null @@ -1,27 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import io.grpc.Context; -//import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -// -//public interface ReadQueueSelector { -// -// SelectableMessageQueue select(Context ctx, ReceiveMessageRequest request, PopMessageRequestHeader requestHeader); -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java deleted file mode 100644 index 6a65c036f8..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/RouteService.java +++ /dev/null @@ -1,150 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Assignment; -//import apache.rocketmq.v2.Broker; -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Endpoints; -//import apache.rocketmq.v2.MessageQueue; -//import apache.rocketmq.v2.Permission; -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import apache.rocketmq.v2.QueryAssignmentResponse; -//import apache.rocketmq.v2.QueryRouteRequest; -//import apache.rocketmq.v2.QueryRouteResponse; -//import io.grpc.Context; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import org.apache.rocketmq.common.protocol.route.QueueData; -//import org.apache.rocketmq.common.protocol.route.TopicRouteData; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.route.MessageQueueView; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -// -//public class RouteService extends AbstractRouteService { -// public RouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { -// super(serviceManager, grpcClientManager); -// } -// -// @Override -// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (queryRouteHook != null) { -// queryRouteHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); -// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); -// List queueDataList = topicRouteData.getQueueDatas(); -// -// List messageQueueList = new ArrayList<>(); -// Endpoints endpoints = request.getEndpoints(); -// Endpoints resEndpoints = this.queryRouteEndpointConverter.convert(ctx, endpoints); -// if (resEndpoints == null || resEndpoints.getDefaultInstanceForType().equals(resEndpoints)) { -// future.complete(QueryRouteResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + -// endpoints + " is invalidate")) -// .build()); -// return future; -// } -// for (QueueData queueData : queueDataList) { -// Broker broker = Broker.newBuilder() -// .setName(queueData.getBrokerName()) -// .setId(0) -// .setEndpoints(resEndpoints) -// .build(); -// -// messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); -// } -// QueryRouteResponse response = QueryRouteResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .addAllMessageQueues(messageQueueList) -// .build(); -// future.complete(response); -// } catch (Throwable t) { -// if (TopicRouteHelper.isTopicNotExistError(t)) { -// future.complete(QueryRouteResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) -// .build()); -// } else { -// future.completeExceptionally(t); -// } -// } -// return future; -// } -// -// @Override -// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (queryAssignmentHook != null) { -// queryAssignmentHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// List assignments = new ArrayList<>(); -// List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); -// Endpoints endpoints = request.getEndpoints(); -// Endpoints resEndpoints = this.queryAssignmentEndpointConverter.convert(ctx, endpoints); -// if (resEndpoints == null || Endpoints.getDefaultInstance().equals(resEndpoints)) { -// future.complete(QueryAssignmentResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_ACCESS_POINT, "endpoint " + -// endpoints + " is invalidate")) -// .build()); -// return future; -// } -// for (SelectableMessageQueue messageQueue : messageQueueList) { -// Broker broker = Broker.newBuilder() -// .setName(messageQueue.getBrokerName()) -// .setId(0) -// .setEndpoints(resEndpoints) -// .build(); -// -// MessageQueue defaultMessageQueue = MessageQueue.newBuilder() -// .setTopic(request.getTopic()) -// .setId(-1) -// .setPermission(Permission.READ_WRITE) -// .setBroker(broker) -// .build(); -// -// assignments.add(Assignment.newBuilder() -// .setMessageQueue(defaultMessageQueue) -// .build()); -// } -// -// QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() -// .addAllAssignments(assignments) -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build(); -// future.complete(response); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java deleted file mode 100644 index 92cf16b0ad..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/TransactionService.java +++ /dev/null @@ -1,139 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.EndTransactionRequest; -//import apache.rocketmq.v2.EndTransactionResponse; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -//import apache.rocketmq.v2.TelemetryCommand; -//import io.grpc.Context; -//import java.util.List; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.ThreadLocalRandom; -//import org.apache.commons.collections.CollectionUtils; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.ForwardProducer; -//import org.apache.rocketmq.proxy.service.transaction.TransactionId; -//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; -//import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseService; -//import org.apache.rocketmq.remoting.common.RemotingHelper; -// -//public class TransactionService extends BaseService implements TransactionStateChecker { -// -// protected final ChannelManager channelManager; -// protected final ForwardProducer forwardProducer; -// -// private volatile ResponseHook checkTransactionStateHook; -// private volatile ResponseHook endTransactionHook; -// -// public TransactionService(ServiceManager serviceManager, ChannelManager channelManager) { -// super(serviceManager); -// this.forwardProducer = serviceManager.getForwardProducer(); -// this.channelManager = channelManager; -// } -// -// @Override -// public void checkTransactionState(TransactionStateCheckRequest checkData) { -// Context ctx = Context.current(); -// try { -// List clientIdList = this.channelManager.getClientIdList(checkData.getGroupId()); -// if (CollectionUtils.isEmpty(clientIdList)) { -// return; -// } -// -// String clientId = clientIdList.get(ThreadLocalRandom.current().nextInt(clientIdList.size())); -// GrpcClientChannel channel = GrpcClientChannel.getChannel(this.channelManager, checkData.getGroupId(), clientId); -// -// String transactionId = checkData.getTransactionId().getProxyTransactionId(); -// MessageExt messageExt = checkData.getMessageExt(); -// Message message = GrpcConverter.buildMessage(messageExt); -// TelemetryCommand response = TelemetryCommand.newBuilder() -// .setRecoverOrphanedTransactionCommand( -// RecoverOrphanedTransactionCommand.newBuilder() -// .setOrphanedTransactionalMessage(message) -// .setTransactionId(transactionId) -// .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, checkData.getBrokerName())) -// .build() -// ).build(); -// -// channel.writeAndFlush(response); -// if (this.checkTransactionStateHook != null) { -// this.checkTransactionStateHook.beforeResponse(ctx, checkData, response, null); -// } -// } catch (Throwable t) { -// if (this.checkTransactionStateHook != null) { -// this.checkTransactionStateHook.beforeResponse(ctx, checkData, null, t); -// } -// } -// } -// -// public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (endTransactionHook != null) { -// endTransactionHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// TransactionId handle = TransactionId.decode(request.getTransactionId()); -// String brokerAddr = RemotingHelper.parseSocketAddressAddr(handle.getBrokerAddr()); -// EndTransactionRequestHeader requestHeader = this.toEndTransactionRequestHeader(ctx, request); -// this.forwardProducer.endTransaction(ctx, brokerAddr, requestHeader); -// future.complete(EndTransactionResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build()); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -// -// protected EndTransactionRequestHeader toEndTransactionRequestHeader(Context ctx, EndTransactionRequest request) { -// String topic = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// // use topic name as producerGroup -// return GrpcConverter.buildEndTransactionRequestHeader(request, topic); -// } -// -// public ResponseHook getCheckTransactionStateHook() { -// return checkTransactionStateHook; -// } -// -// public void setCheckTransactionStateHook( -// ResponseHook checkTransactionStateHook) { -// this.checkTransactionStateHook = checkTransactionStateHook; -// } -// -// public ResponseHook getEndTransactionHook() { -// return endTransactionHook; -// } -// -// public void setEndTransactionHook( -// ResponseHook endTransactionHook) { -// this.endTransactionHook = endTransactionHook; -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java deleted file mode 100644 index 853bb1df2a..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/cluster/WriteQueueSelector.java +++ /dev/null @@ -1,26 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.SendMessageRequest; -//import io.grpc.Context; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -// -//public interface WriteQueueSelector { -// -// SelectableMessageQueue selectQueue(Context ctx, SendMessageRequest request); -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java deleted file mode 100644 index 4f32b0aed2..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriter.java +++ /dev/null @@ -1,76 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.Context; -//import io.grpc.stub.StreamObserver; -//import io.netty.channel.Channel; -//import org.apache.rocketmq.broker.BrokerController; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.protocol.RequestCode; -//import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseHook; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResponseStreamWriter; -//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -//import org.apache.rocketmq.remoting.exception.RemotingCommandException; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -// -//public class LocalReceiveMessageResponseStreamWriter extends BaseReceiveMessageResponseStreamWriter { -// private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// private final ChannelManager channelManager; -// private final BrokerController brokerController; -// -// public LocalReceiveMessageResponseStreamWriter( -// StreamObserver observer, -// ResponseHook hook, -// ChannelManager channelManager, -// BrokerController brokerController, -// ReceiveMessageResultFilter receiveMessageResultFilter) { -// super(observer, hook, receiveMessageResultFilter); -// this.channelManager = channelManager; -// this.brokerController = brokerController; -// } -// -// @Override -// protected void processThrowableWhenWriteMessage(Throwable throwable, Context context, ReceiveMessageRequest request, -// Message message) { -// this.changeInvisibleTime(context, request, ReceiptHandle.decode(message.getSystemProperties().getReceiptHandle())); -// } -// -// private void changeInvisibleTime(Context ctx, ReceiveMessageRequest request, ReceiptHandle handle) { -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); -// ChangeInvisibleTimeRequestHeader requestHeader = GrpcConverter.buildChangeInvisibleTimeRequestHeader(request, handle); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); -// command.makeCustomHeaderToNet(); -// try { -// brokerController.getChangeInvisibleTimeProcessor().processRequest(simpleChannelHandlerContext, command); -// } catch (RemotingCommandException e) { -// log.error("ChangeInvisibleTime error when write response", e); -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java deleted file mode 100644 index 2b62522856..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalReceiveMessageResultFilter.java +++ /dev/null @@ -1,94 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import io.grpc.Context; -//import io.netty.channel.Channel; -//import org.apache.rocketmq.broker.BrokerController; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.RequestCode; -//import org.apache.rocketmq.common.protocol.ResponseCode; -//import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; -//import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.channel.SimpleChannelHandlerContext; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.service.BaseReceiveMessageResultFilter; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -//import org.apache.rocketmq.remoting.exception.RemotingCommandException; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -// -//public class LocalReceiveMessageResultFilter extends BaseReceiveMessageResultFilter { -// private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// -// private final ChannelManager channelManager; -// private final BrokerController brokerController; -// -// public LocalReceiveMessageResultFilter(ChannelManager channelManager, BrokerController brokerController, GrpcClientManager grpcClientManager) { -// super(grpcClientManager); -// this.channelManager = channelManager; -// this.brokerController = brokerController; -// } -// -// @Override -// protected void processNoMatchMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt) { -// ReceiptHandle handle = ReceiptHandle.create(messageExt); -// if (handle == null) { -// return; -// } -// Channel channel = channelManager.createChannel(ctx); -// AckMessageRequestHeader requestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); -// command.makeCustomHeaderToNet(); -// try { -// brokerController.getAckMessageProcessor().processRequest(new SimpleChannelHandlerContext(channel), command); -// } catch (RemotingCommandException e) { -// log.error("AckMessage failed in filterMessage", e); -// } -// } -// -// @Override -// protected void processExceedMaxAttemptsMessage(Context ctx, ReceiveMessageRequest request, MessageExt messageExt, -// int maxAttempts) { -// try { -// ReceiptHandle handle = ReceiptHandle.create(messageExt); -// if (handle == null) { -// return; -// } -// Channel channel = channelManager.createChannel(ctx); -// SimpleChannelHandlerContext simpleChannelHandlerContext = new SimpleChannelHandlerContext(channel); -// ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = GrpcConverter.buildConsumerSendMsgBackRequestHeader(request, handle, messageExt.getMsgId(), maxAttempts); -// RemotingCommand command = RemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, consumerSendMsgBackRequestHeader); -// command.makeCustomHeaderToNet(); -// RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, command); -// if (response.getCode() == ResponseCode.SUCCESS) { -// AckMessageRequestHeader ackMessageRequestHeader = GrpcConverter.buildAckMessageRequestHeader(request, handle); -// command = RemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, ackMessageRequestHeader); -// command.makeCustomHeaderToNet(); -// brokerController.getAckMessageProcessor().processRequest(simpleChannelHandlerContext, command); -// } -// } catch (Exception e) { -// log.error("ForwardMessageToDLQ failed in filterMessage", e); -// } -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java b/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java deleted file mode 100644 index 0553ba39da..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/local/LocalWriteQueueSelector.java +++ /dev/null @@ -1,101 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.SendMessageRequest; -//import com.google.common.hash.Hashing; -//import io.grpc.Context; -//import java.util.Random; -//import java.util.concurrent.atomic.AtomicInteger; -//import org.apache.commons.lang3.StringUtils; -//import org.apache.rocketmq.broker.topic.TopicConfigManager; -//import org.apache.rocketmq.common.TopicConfig; -//import org.apache.rocketmq.common.constant.LoggerName; -//import org.apache.rocketmq.common.message.MessageQueue; -//import org.apache.rocketmq.logging.InternalLogger; -//import org.apache.rocketmq.logging.InternalLoggerFactory; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -//import org.apache.rocketmq.proxy.grpc.v2.service.cluster.DefaultWriteQueueSelector; -// -//public class LocalWriteQueueSelector extends DefaultWriteQueueSelector { -// private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); -// private final String brokerName; -// private final AtomicInteger queueIndex; -// private final TopicConfigManager topicConfigManager; -// -// public LocalWriteQueueSelector(String brokerName, TopicConfigManager topicConfigManager, TopicRouteService topicRouteService) { -// super(topicRouteService); -// this.brokerName = brokerName; -// this.queueIndex = new AtomicInteger(Math.abs(new Random().nextInt())); -// this.topicConfigManager = topicConfigManager; -// } -// -// @Override -// public SelectableMessageQueue selectQueue( -// Context ctx, -// SendMessageRequest request -// ) { -// try { -// if (request.getMessagesCount() <= 0) { -// throw new ProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); -// } -// Message message = request.getMessages(0); -// String topic = GrpcConverter.wrapResourceWithNamespace(message.getTopic()); -// String shardingKey = null; -// if (request.getMessagesCount() == 1) { -// shardingKey = message.getSystemProperties().getMessageGroup(); -// } -// SelectableMessageQueue targetMessageQueue; -// if (StringUtils.isNotEmpty(shardingKey)) { -// // With shardingKey -// targetMessageQueue = selectOrderQueue(topic, shardingKey); -// } else { -// targetMessageQueue = selectNormalQueue(topic); -// } -// return targetMessageQueue; -// } catch (Exception e) { -// log.error("error when select queue in DefaultMessageQueueSelector. request: {}", request, e); -// return null; -// } -// } -// -// protected SelectableMessageQueue selectNormalQueue(String topic) throws Exception { -// TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); -// if (topicConfig == null) { -// throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); -// } -// int selectQueueId = queueIndex.getAndIncrement() % topicConfig.getWriteQueueNums(); -// MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); -// return new SelectableMessageQueue(mq, null); -// } -// -// protected SelectableMessageQueue selectOrderQueue(String topic, String shardingKey) throws Exception { -// TopicConfig topicConfig = topicConfigManager.selectTopicConfig(topic); -// if (topicConfig == null) { -// throw new ProxyException(Code.TOPIC_NOT_FOUND, topic); -// } -// int selectQueueId = Hashing.consistentHash(shardingKey.hashCode(), topicConfig.getWriteQueueNums()); -// MessageQueue mq = new MessageQueue(topic, brokerName, selectQueueId); -// return new SelectableMessageQueue(mq, null); -// } -//} diff --git a/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java b/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java deleted file mode 100644 index 2be0fedb23..0000000000 --- a/proxy/src/test/resources/backup/grpc/v2/service/local/RouteService.java +++ /dev/null @@ -1,175 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.Address; -//import apache.rocketmq.v2.AddressScheme; -//import apache.rocketmq.v2.Assignment; -//import apache.rocketmq.v2.Broker; -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Endpoints; -//import apache.rocketmq.v2.MessageQueue; -//import apache.rocketmq.v2.Permission; -//import apache.rocketmq.v2.QueryAssignmentRequest; -//import apache.rocketmq.v2.QueryAssignmentResponse; -//import apache.rocketmq.v2.QueryRouteRequest; -//import apache.rocketmq.v2.QueryRouteResponse; -//import com.google.common.net.HostAndPort; -//import io.grpc.Context; -//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.common.protocol.route.BrokerData; -//import org.apache.rocketmq.common.protocol.route.QueueData; -//import org.apache.rocketmq.common.protocol.route.TopicRouteData; -//import org.apache.rocketmq.proxy.config.ConfigurationManager; -//import org.apache.rocketmq.proxy.service.ServiceManager; -//import org.apache.rocketmq.proxy.service.route.MessageQueueView; -//import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -//import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.service.AbstractRouteService; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -// -//public class RouteService extends AbstractRouteService { -// public RouteService(ServiceManager serviceManager, GrpcClientManager grpcClientManager) { -// super(serviceManager, grpcClientManager); -// } -// -// @Override -// public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (queryRouteHook != null) { -// queryRouteHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); -// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); -// List queueDataList = topicRouteData.getQueueDatas(); -// List brokerDataList = topicRouteData.getBrokerDatas(); -// -// List messageQueueList = new ArrayList<>(); -// Map> brokerMap = buildBrokerMap(brokerDataList); -// -// for (QueueData queueData : queueDataList) { -// String brokerName = queueData.getBrokerName(); -// Map brokerIdMap = brokerMap.get(brokerName); -// if (brokerIdMap == null) { -// break; -// } -// for (Broker broker : brokerIdMap.values()) { -// messageQueueList.addAll(GrpcConverter.genMessageQueueFromQueueData(queueData, request.getTopic(), broker)); -// } -// } -// -// QueryRouteResponse response = QueryRouteResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .addAllMessageQueues(messageQueueList) -// .build(); -// future.complete(response); -// } catch (Throwable t) { -// if (TopicRouteHelper.isTopicNotExistError(t)) { -// future.complete(QueryRouteResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) -// .build()); -// } else { -// future.completeExceptionally(t); -// } -// } -// return future; -// } -// -// @Override -// public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { -// CompletableFuture future = new CompletableFuture<>(); -// future.whenComplete((response, throwable) -> { -// if (queryAssignmentHook != null) { -// queryAssignmentHook.beforeResponse(ctx, request, response, throwable); -// } -// }); -// -// try { -// List assignments = new ArrayList<>(); -// List messageQueueList = this.assignmentQueueSelector.getAssignment(ctx, request); -// String topicName = GrpcConverter.wrapResourceWithNamespace(request.getTopic()); -// MessageQueueView messageQueueView = this.serviceManager.getTopicRouteService().getAllMessageQueueView(topicName); -// TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); -// Map> brokerMap = buildBrokerMap(topicRouteData.getBrokerDatas()); -// for (SelectableMessageQueue messageQueue : messageQueueList) { -// Map brokerIdMap = brokerMap.get(messageQueue.getBrokerName()); -// if (brokerIdMap != null) { -// Broker broker = brokerIdMap.get(0L); -// -// MessageQueue defaultMessageQueue = MessageQueue.newBuilder() -// .setTopic(request.getTopic()) -// .setId(-1) -// .setPermission(Permission.READ_WRITE) -// .setBroker(broker) -// .build(); -// -// assignments.add(Assignment.newBuilder() -// .setMessageQueue(defaultMessageQueue) -// .build()); -// } -// } -// QueryAssignmentResponse response = QueryAssignmentResponse.newBuilder() -// .addAllAssignments(assignments) -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) -// .build(); -// future.complete(response); -// } catch (Throwable t) { -// future.completeExceptionally(t); -// } -// return future; -// } -// -// private Map> buildBrokerMap(List brokerDataList) { -// Map> brokerMap = new HashMap<>(); -// for (BrokerData brokerData : brokerDataList) { -// Map brokerIdMap = new HashMap<>(); -// String brokerName = brokerData.getBrokerName(); -// for (Map.Entry entry : brokerData.getBrokerAddrs().entrySet()) { -// Long brokerId = entry.getKey(); -// HostAndPort hostAndPort = HostAndPort.fromString(entry.getValue()); -// Broker broker = Broker.newBuilder() -// .setName(brokerName) -// .setId(Math.toIntExact(brokerId)) -// .setEndpoints(Endpoints.newBuilder() -// .setScheme(AddressScheme.IPv4) -// .addAddresses( -// Address.newBuilder() -// .setPort(ConfigurationManager.getProxyConfig().getGrpcServerPort()) -// .setHost(hostAndPort.getHost()) -// ) -// .build()) -// .build(); -// -// brokerIdMap.put(brokerId, broker); -// } -// brokerMap.put(brokerName, brokerIdMap); -// } -// return brokerMap; -// } -//} diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java deleted file mode 100644 index b1760e52f1..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/LocalGrpcServiceTest.java +++ /dev/null @@ -1,524 +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.proxy.grpc.v2.service; - -import apache.rocketmq.v2.AckMessageEntry; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.EndTransactionRequest; -import apache.rocketmq.v2.EndTransactionResponse; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; -import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import apache.rocketmq.v2.HeartbeatRequest; -import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.NotifyClientTerminationRequest; -import apache.rocketmq.v2.Publishing; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.RetryPolicy; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; -import apache.rocketmq.v2.SystemProperties; -import apache.rocketmq.v2.TelemetryCommand; -import apache.rocketmq.v2.ThreadStackTrace; -import apache.rocketmq.v2.VerifyMessageResult; -import io.grpc.Context; -import io.grpc.Metadata; -import io.grpc.stub.ServerCallStreamObserver; -import io.grpc.stub.StreamObserver; -import io.netty.channel.ChannelHandlerContext; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.broker.BrokerController; -import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; -import org.apache.rocketmq.broker.client.ConsumerManager; -import org.apache.rocketmq.broker.client.ProducerChangeListener; -import org.apache.rocketmq.broker.client.ProducerManager; -import org.apache.rocketmq.broker.processor.AckMessageProcessor; -import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; -import org.apache.rocketmq.broker.processor.ClientManageProcessor; -import org.apache.rocketmq.broker.processor.EndTransactionProcessor; -import org.apache.rocketmq.broker.processor.PopMessageProcessor; -import org.apache.rocketmq.broker.processor.PullMessageProcessor; -import org.apache.rocketmq.broker.processor.SendMessageProcessor; -import org.apache.rocketmq.broker.topic.TopicConfigManager; -import org.apache.rocketmq.common.BrokerConfig; -import org.apache.rocketmq.common.ThreadFactoryImpl; -import org.apache.rocketmq.common.TopicConfig; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.protocol.RequestCode; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; -import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; -import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -import org.apache.rocketmq.proxy.common.TelemetryCommandRecord; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -import org.apache.rocketmq.remoting.exception.RemotingCommandException; -import org.apache.rocketmq.remoting.netty.NettyRemotingServer; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -@RunWith(MockitoJUnitRunner.class) -public class LocalGrpcServiceTest extends InitConfigAndLoggerTest { - private LocalGrpcActivity localGrpcService; - @Mock - private SendMessageProcessor sendMessageProcessorMock; - @Mock - private PopMessageProcessor popMessageProcessorMock; - @Mock - private PullMessageProcessor pullMessageProcessorMock; - @Mock - private BrokerController brokerControllerMock; - @Mock - private ConsumerManager consumerManagerMock; - @Mock - private ProducerManager producerManagerMock; - @Mock - private TopicConfigManager topicConfigManagerMock; - - @Mock - private TelemetryCommandManager telemetryCommandManager; - - StreamObserver receiveStreamObserver = Mockito.mock(ServerCallStreamObserver.class); - - private Metadata metadata; - - private StreamObserver streamObserver; - - @Before - public void setUp() throws Throwable { - super.before(); - ConfigurationManager.getProxyConfig().setNameSrvAddr("1.1.1.1"); - Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); - Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); - Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); - Mockito.when(brokerControllerMock.getTopicConfigManager()).thenReturn(topicConfigManagerMock); - Mockito.when(topicConfigManagerMock.selectTopicConfig(Mockito.anyString())).thenReturn(new TopicConfig("topic", 8, 8)); - Mockito.doNothing().when(consumerManagerMock).appendConsumerIdsChangeListener(Mockito.any(ConsumerIdsChangeListener.class)); - Mockito.doNothing().when(producerManagerMock).appendProducerChangeListener(Mockito.any(ProducerChangeListener.class)); - Mockito.when(brokerControllerMock.getConsumerManager()).thenReturn(consumerManagerMock); - Mockito.when(brokerControllerMock.getProducerManager()).thenReturn(producerManagerMock); - localGrpcService = new LocalGrpcActivity(brokerControllerMock, telemetryCommandManager); - metadata = new Metadata(); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, "1.1.1.1"); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, "0.0.0.0"); - metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); - metadata.put(InterceptorConstants.CLIENT_ID, "client-id"); - Context.current().withValue(InterceptorConstants.METADATA, metadata).attach(); - streamObserver = localGrpcService.telemetry(Context.current(), new StreamObserver() { - @Override public void onNext(TelemetryCommand value) { - } - - @Override public void onError(Throwable t) { - } - - @Override public void onCompleted() { - } - }); - streamObserver.onNext(TelemetryCommand.newBuilder() - .setSettings(Settings.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(3).build()) - .setSubscription(Subscription.newBuilder().build()) - .build()).build()); - } - - @Test - public void testHeartbeatProducerData() throws Exception { - streamObserver.onNext(TelemetryCommand.newBuilder() - .setSettings(Settings.newBuilder() - .setPublishing(Publishing.newBuilder() - .addTopics(Resource.newBuilder() - .setName("topic") - .build()) - .build()) - .setClientType(ClientType.PRODUCER) - .build()) - .build()); - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); - Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); - HeartbeatRequest request = HeartbeatRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build(); - CompletableFuture grpcFuture = localGrpcService.heartbeat(Context.current(), request); - HeartbeatResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()) - .isEqualTo(Code.OK); - } - - @Test - public void testHeartbeatConsumerData() throws Exception { - streamObserver.onNext(TelemetryCommand.newBuilder() - .setSettings(Settings.newBuilder() - .setClientType(ClientType.PUSH_CONSUMER).build()) - .build()); - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - ClientManageProcessor clientManageProcessorMock = Mockito.mock(ClientManageProcessor.class); - Mockito.when(clientManageProcessorMock.heartBeat(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessorMock); - HeartbeatRequest request = HeartbeatRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build(); - CompletableFuture grpcFuture = localGrpcService.heartbeat(Context.current(), request); - HeartbeatResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()) - .isEqualTo(Code.OK); - } - - @Test - public void testSendMessageError() throws Exception { - String remark = "store putMessage return null"; - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SYSTEM_ERROR, remark); - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(0, Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("123") - .build()) - .build()) - .build(); - - CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current(), request); - SendMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()) - .isEqualTo(Code.INTERNAL_SERVER_ERROR); - } - - @Test - public void testSendMessageWriteAndFlush() throws Exception { - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(null); - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(0, Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("123") - .build()) - .build()) - .build(); - - CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current(), request); - assertThat(grpcFuture.isDone()).isFalse(); - } - - @Test - public void testSendMessageBatchWithWriteAndFlush() throws Exception { - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(null); - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("123") - .build()) - .build()) - .addMessages(Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("124") - .build()) - .build()) - .build(); - - CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current(), request); - assertThat(grpcFuture.isDone()).isFalse(); - } - - @Test - public void testSendMessageWithException() throws Exception { - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenThrow(new RemotingCommandException("test")); - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(0, Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("123") - .build()) - .build()) - .build(); - - CompletableFuture grpcFuture = localGrpcService.sendMessage( - Context.current(), request); - assertThatThrownBy(() -> { - try { - grpcFuture.get(); - } catch (ExecutionException e) { - throw e.getCause(); - } - }).isInstanceOf(RemotingCommandException.class); - } - - @Test - public void testReceiveMessageSuccess() throws Exception { - long invisibleTime = 1000L; - String topic = "topic"; - byte[] body = "123".getBytes(StandardCharsets.UTF_8); - MessageExt messageExt = new MessageExt(); - messageExt.setTopic(topic); - messageExt.setQueueOffset(0L); - messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); - messageExt.setBody(body); - messageExt.putUserProperty("key", "value"); - PopMessageResponseHeader responseHeader = new PopMessageResponseHeader(); - responseHeader.setInvisibleTime(invisibleTime); - RemotingCommand remotingCommand = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); - remotingCommand.setBody(MessageDecoder.encode(messageExt, true)); - remotingCommand.makeCustomHeaderToNet(); - Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(remotingCommand); - ReceiveMessageRequest request = ReceiveMessageRequest.newBuilder() - .setMessageQueue(MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setName(topic) - .build()) - .build()) - .build(); - ReceiveMessageResponse receiveMessageResponse1 = ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build(); - Message message = GrpcConverter.buildMessage(messageExt); - ReceiveMessageResponse receiveMessageResponse2 = ReceiveMessageResponse.newBuilder() - .setMessage(message.toBuilder() - .setSystemProperties( - message.getSystemProperties() - .toBuilder() - .setReceiptHandle("0 0 1000 0 0 "+ brokerControllerMock.getBrokerConfig().getBrokerName() +" 0 0 0") - .build()) - .build()) - .build(); - Mockito.doNothing().when(receiveStreamObserver).onNext(Mockito.any()); - localGrpcService.receiveMessage(Context.current().withDeadlineAfter(20, TimeUnit.SECONDS, - Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("test"))), request, receiveStreamObserver); - ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); - Mockito.verify(receiveStreamObserver, Mockito.times(2)).onNext(argument.capture()); - assertThat(argument.getAllValues().get(0)).isEqualTo(receiveMessageResponse1); - assertThat(argument.getAllValues().get(1)).isEqualTo(receiveMessageResponse2); - } - - @Test - public void testAckMessage() throws Exception { - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - AckMessageProcessor ackMessageProcessorMock = Mockito.mock(AckMessageProcessor.class); - Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); - Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - AckMessageRequest request = AckMessageRequest.newBuilder() - .addEntries( - AckMessageEntry.newBuilder() - .setReceiptHandle(ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(System.currentTimeMillis()) - .invisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()) - .build()) - .build(); - CompletableFuture grpcFuture = localGrpcService.ackMessage(Context.current(), request); - AckMessageResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - } - - @Test - public void testForwardMessageToDeadLetterQueue() throws Exception { - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); - Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(ChannelHandlerContext.class), - Mockito.argThat(argument -> argument.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK))) - .thenReturn(response); - ForwardMessageToDeadLetterQueueRequest request = ForwardMessageToDeadLetterQueueRequest.newBuilder() - .setReceiptHandle(ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(1000L) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(0) - .offset(0L) - .build().encode()) - .build(); - CompletableFuture grpcFuture = localGrpcService.forwardMessageToDeadLetterQueue( - Context.current(), request); - ForwardMessageToDeadLetterQueueResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - } - - @Test - public void testEndTransaction() throws Exception { - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - - EndTransactionProcessor endTransactionProcessor = Mockito.mock(EndTransactionProcessor.class); - Mockito.when(brokerControllerMock.getEndTransactionProcessor()).thenReturn(endTransactionProcessor); - Mockito.when(endTransactionProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), - Mockito.any(RemotingCommand.class))) - .thenReturn(response); - EndTransactionRequest request = EndTransactionRequest.newBuilder() - .setMessageId("123") - .setTransactionId(TransactionId.genByBrokerTransactionId( - new InetSocketAddress("0.0.0.0", 80), "123", 123, 123 - ).getProxyTransactionId() - ) - .build(); - CompletableFuture grpcFuture = localGrpcService.endTransaction( - Context.current(), request); - EndTransactionResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - } - - @Test - public void testReportThreadStackTrace() throws Exception { - int opaque = 1; - String nonce = "123"; - NettyRemotingServer remotingServerMock = Mockito.mock(NettyRemotingServer.class); - Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(remotingServerMock); - Mockito.doNothing().when(remotingServerMock).processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); - Mockito.when(telemetryCommandManager.getCommand(Mockito.eq(nonce))).thenReturn(new TelemetryCommandRecord(nonce, opaque)); - String jstack = "jstack"; - - streamObserver.onNext(TelemetryCommand.newBuilder() - .setThreadStackTrace(ThreadStackTrace.newBuilder() - .setNonce(nonce) - .setThreadStackTrace(jstack).build()) - .build()); - Mockito.verify(remotingServerMock, Mockito.times(1)) - .processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); - } - - @Test - public void testReportVerifyMessageResult() { - int opaque = 1; - String nonce = "123"; - NettyRemotingServer remotingServerMock = Mockito.mock(NettyRemotingServer.class); - Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(remotingServerMock); - Mockito.doNothing().when(remotingServerMock).processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); - Mockito.when(telemetryCommandManager.getCommand(Mockito.eq(nonce))).thenReturn(new TelemetryCommandRecord(nonce, opaque)); - - streamObserver.onNext(TelemetryCommand.newBuilder() - .setVerifyMessageResult(VerifyMessageResult.newBuilder() - .setNonce(nonce) - .setStatus(ResponseBuilder.buildStatus(Code.OK, "ok")).build()) - .build()); - Mockito.verify(remotingServerMock, Mockito.times(1)) - .processResponseCommand(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); - } - - @Test - public void testNotifyClientTermination() throws Exception { - RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); - - ClientManageProcessor clientManageProcessor = Mockito.mock(ClientManageProcessor.class); - Mockito.when(brokerControllerMock.getClientManageProcessor()).thenReturn(clientManageProcessor); - Mockito.when(clientManageProcessor.unregisterClient(Mockito.any(ChannelHandlerContext.class), - Mockito.any(RemotingCommand.class))) - .thenReturn(response); - NotifyClientTerminationRequest request = NotifyClientTerminationRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build(); - localGrpcService.notifyClientTermination( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); - Mockito.verify(clientManageProcessor, Mockito.times(1)) - .unregisterClient(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class)); - } - - @Test - public void testChangeInvisibleDuration() throws Exception { - long invisibleTime = 1000L; - int queueId = 1; - long offset = 123L; - ChangeInvisibleTimeResponseHeader responseHeader = new ChangeInvisibleTimeResponseHeader(); - responseHeader.setInvisibleTime(1000L); - responseHeader.setPopTime(0L); - responseHeader.setReviveQid(0); - RemotingCommand response = RemotingCommand.createResponseCommandWithHeader(ResponseCode.SUCCESS, responseHeader); - - ChangeInvisibleTimeProcessor changeInvisibleTimeProcessor = Mockito.mock(ChangeInvisibleTimeProcessor.class); - Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessor); - Mockito.when(changeInvisibleTimeProcessor.processRequest(Mockito.any(ChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) - .thenReturn(response); - ChangeInvisibleDurationRequest request = ChangeInvisibleDurationRequest.newBuilder().setReceiptHandle( - ReceiptHandle.builder() - .startOffset(0L) - .retrieveTime(0L) - .invisibleTime(invisibleTime) - .nextVisibleTime(1000L) - .reviveQueueId(0) - .topicType("topic") - .brokerName("brokerName") - .queueId(queueId) - .offset(offset) - .build().encode() - ).build(); - CompletableFuture grpcFuture = localGrpcService.changeInvisibleDuration( - Context.current() - .withValue(InterceptorConstants.METADATA, metadata) - .attach(), request); - ChangeInvisibleDurationResponse r = grpcFuture.get(); - assertThat(r.getStatus().getCode()).isEqualTo(Code.OK); - ReceiptHandle handle = ReceiptHandle.decode(r.getReceiptHandle()); - assertThat(handle.getInvisibleTime()).isEqualTo(invisibleTime); - assertThat(handle.getQueueId()).isEqualTo(queueId); - assertThat(handle.getOffset()).isEqualTo(offset); - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java deleted file mode 100644 index 3be07c9518..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/BaseServiceTest.java +++ /dev/null @@ -1,132 +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.proxy.grpc.v2.service.cluster; - -import io.grpc.Context; -import io.grpc.Metadata; -import java.net.SocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageAccessor; -import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.apache.rocketmq.proxy.service.ServiceManager; -import org.apache.rocketmq.proxy.service.DefaultForwardClient; -import org.apache.rocketmq.proxy.service.ForwardProducer; -import org.apache.rocketmq.proxy.service.ForwardReadConsumer; -import org.apache.rocketmq.proxy.service.ForwardWriteConsumer; -import org.apache.rocketmq.proxy.service.route.TopicRouteService; -import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; -import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -import org.apache.rocketmq.remoting.common.RemotingUtil; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.mockito.Mockito.when; - -@Ignore -@RunWith(MockitoJUnitRunner.Silent.class) -public abstract class BaseServiceTest extends InitConfigAndLoggerTest { - - @Mock - protected ServiceManager serviceManager; - @Mock - protected DefaultForwardClient defaultClient; - @Mock - protected ForwardProducer producerClient; - @Mock - protected ForwardReadConsumer readConsumerClient; - @Mock - protected ForwardWriteConsumer writeConsumerClient; - @Mock - protected TopicRouteService topicRouteService; - @Mock - protected ClusterTransactionService clusterTransactionService; - @Mock - protected GrpcClientManager grpcClientManager; - - public static final String REMOTE_ADDRESS = "1.1.1.1"; - public static final String LOCAL_ADDRESS = "0.0.0.0"; - public static final String LANGUAGE = "JAVA"; - public static final String CLIENT_ID = "client-id"; - - @Before - public void before() throws Throwable { - super.before(); - when(serviceManager.getDefaultForwardClient()).thenReturn(defaultClient); - when(serviceManager.getForwardProducer()).thenReturn(producerClient); - when(serviceManager.getForwardReadConsumer()).thenReturn(readConsumerClient); - when(serviceManager.getForwardWriteConsumer()).thenReturn(writeConsumerClient); - when(serviceManager.getTopicRouteService()).thenReturn(topicRouteService); - when(serviceManager.getTransactionHeartbeatRegisterService()).thenReturn(clusterTransactionService); - - initContext(); - beforeEach(); - } - - public abstract void beforeEach() throws Throwable; - - protected static ReceiptHandle createReceiptHandle() { - return ReceiptHandle.builder() - .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName("brokerName") - .retrieveTime(System.currentTimeMillis()) - .invisibleTime(TimeUnit.SECONDS.toMillis(3)) - .queueId(ThreadLocalRandom.current().nextInt(8)) - .offset(ThreadLocalRandom.current().nextInt(1000)) - .commitLogOffset(ThreadLocalRandom.current().nextInt(1000)) - .build(); - } - - protected static MessageExt createMessageExt(String msgId, String tag) { - return createMessageExt(msgId, tag, createReceiptHandle().encode()); - } - - protected static MessageExt createMessageExt(String msgId, String tag, String handler) { - SocketAddress addr = RemotingUtil.string2SocketAddress("127.0.0.1:8080"); - MessageExt msg = new MessageExt(0, - System.currentTimeMillis(), - addr, - System.currentTimeMillis(), - addr, - msgId); - msg.setTopic("topic"); - msg.setBody("hello".getBytes(StandardCharsets.UTF_8)); - MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TAGS, tag); - MessageAccessor.putProperty(msg, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, msgId); - MessageAccessor.putProperty(msg, MessageConst.PROPERTY_POP_CK, handler); - return msg; - } - - protected static Context initContext() { - Context ctx = Context.current(); - Metadata metadata = new Metadata(); - metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDRESS); - metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDRESS); - metadata.put(InterceptorConstants.LANGUAGE, LANGUAGE); - metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); - ctx.withValue(InterceptorConstants.METADATA, metadata).attach(); - return ctx; - } -} diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java deleted file mode 100644 index 65cad72e35..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ConsumerServiceTest.java +++ /dev/null @@ -1,274 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.AckMessageEntry; -import apache.rocketmq.v2.AckMessageRequest; -import apache.rocketmq.v2.AckMessageResponse; -import apache.rocketmq.v2.ChangeInvisibleDurationRequest; -import apache.rocketmq.v2.ChangeInvisibleDurationResponse; -import apache.rocketmq.v2.ClientType; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.FilterExpression; -import apache.rocketmq.v2.FilterType; -import apache.rocketmq.v2.ReceiveMessageRequest; -import apache.rocketmq.v2.ReceiveMessageResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.RetryPolicy; -import apache.rocketmq.v2.Settings; -import apache.rocketmq.v2.Subscription; -import com.google.protobuf.Duration; -import com.google.protobuf.util.Durations; -import io.grpc.Context; -import io.grpc.stub.StreamObserver; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import org.apache.rocketmq.client.consumer.AckResult; -import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.client.consumer.PopResult; -import org.apache.rocketmq.client.consumer.PopStatus; -import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.assertj.core.util.Lists; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ConsumerServiceTest extends BaseServiceTest { - - @Mock - private ReadQueueSelector readQueueSelector; - @Mock - private StreamObserver receiveMessageResponseStreamObserver; - - private ConsumerService consumerService; - private DefaultReceiveMessageResultFilter receiveMessageResultFilter; - - @Override - public void beforeEach() throws Throwable { - consumerService = new ConsumerService(this.serviceManager, this.grpcClientManager); - consumerService.start(); - - receiveMessageResultFilter = new DefaultReceiveMessageResultFilter(producerClient, writeConsumerClient, grpcClientManager, topicRouteService); - consumerService.setReceiveMessageWriterBuilder((observer, hook) -> - new DefaultReceiveMessageResponseStreamWriter(observer, hook, writeConsumerClient, topicRouteService, receiveMessageResultFilter)); - consumerService.setReadQueueSelector(readQueueSelector); - } - - @Test - public void testReceiveMessage() throws Exception { - SelectableMessageQueue selectableMessageQueue = new SelectableMessageQueue( - new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); - when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); - - Settings clientSettings = Settings.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(16).build()) - .setSubscription(Subscription.newBuilder() - .setFifo(false) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - - List messageExtList = Lists.newArrayList( - createMessageExt("msg1", "msg1"), - createMessageExt("msg2", "msg2") - ); - PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); - when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) - .thenReturn(CompletableFuture.completedFuture(popResult)); - when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())) - .thenReturn(CompletableFuture.completedFuture(new AckResult())); - - Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); - AtomicReference ackHandler = new AtomicReference<>(); - receiveMessageResultFilter.setAckNoMatchedMessageHook((ctx1, request, response, t) -> ackHandler.set(request.getExtraInfo())); - consumerService.receiveMessage(ctx, - ReceiveMessageRequest.newBuilder() - .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .build()) - .setFilterExpression(FilterExpression.newBuilder() - .setType(FilterType.TAG) - .setExpression("msg1") - .build()) - .build(), - receiveMessageResponseStreamObserver - ); - ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); - verify(receiveMessageResponseStreamObserver, times(2)).onNext(argument.capture()); - verify(receiveMessageResponseStreamObserver, times(1)).onCompleted(); - - ReceiveMessageResponse response = argument.getAllValues().get(0); - assertTrue(response.hasStatus()); - assertEquals(Code.OK, response.getStatus().getCode()); - - response = argument.getAllValues().get(1); - assertTrue(response.hasMessage()); - assertEquals("msg1", response.getMessage().getSystemProperties().getMessageId()); - assertEquals(ReceiptHandle.create(messageExtList.get(1)).getReceiptHandle(), ackHandler.get()); - } - - @Test - public void testToDLQInReceiveMessage() throws Exception { - SelectableMessageQueue selectableMessageQueue = new SelectableMessageQueue( - new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr"); - when(readQueueSelector.select(any(), any(), any())).thenReturn(selectableMessageQueue); - - Settings clientSettings = Settings.newBuilder() - .setClientType(ClientType.SIMPLE_CONSUMER) - .setBackoffPolicy(RetryPolicy.newBuilder().setMaxAttempts(0).build()) - .setSubscription(Subscription.newBuilder() - .setFifo(false) - .build()) - .build(); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - - List messageExtList = Lists.newArrayList( - createMessageExt("msg1", "msg1"), - createMessageExt("msg2", "msg2") - ); - PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); - when(readConsumerClient.popMessage(any(), anyString(), anyString(), any(), anyLong())) - .thenReturn(CompletableFuture.completedFuture(popResult)); - when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - ArgumentCaptor sendMsgBackRequestHeaderArgumentCaptor = - ArgumentCaptor.forClass(ConsumerSendMsgBackRequestHeader.class); - when(producerClient.sendMessageBackThenAckOrg(any(), anyString(), sendMsgBackRequestHeaderArgumentCaptor.capture(), any())) - .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); - when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())) - .thenReturn(CompletableFuture.completedFuture(new AckResult())); - - Context ctx = Context.current().withDeadlineAfter(3, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); - consumerService.receiveMessage(ctx, - ReceiveMessageRequest.newBuilder() - .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .build()) - .setFilterExpression(FilterExpression.newBuilder() - .setType(FilterType.TAG) - .setExpression("*") - .build()) - .build(), - receiveMessageResponseStreamObserver - ); - ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); - verify(receiveMessageResponseStreamObserver, times(1)).onNext(argument.capture()); - verify(receiveMessageResponseStreamObserver, times(1)).onCompleted(); - - ReceiveMessageResponse response = argument.getValue(); - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(2, sendMsgBackRequestHeaderArgumentCaptor.getAllValues().size()); - Set toDLQMsgId = sendMsgBackRequestHeaderArgumentCaptor.getAllValues().stream() - .map(ConsumerSendMsgBackRequestHeader::getOriginMsgId).collect(Collectors.toSet()); - assertTrue(toDLQMsgId.contains("msg1")); - assertTrue(toDLQMsgId.contains("msg2")); - } - - @Test - public void testAckMessage() throws Exception { - when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - AckResult ackResult = new AckResult(); - ackResult.setStatus(AckStatus.OK); - when(writeConsumerClient.ackMessage(any(), anyString(), anyString(), any())).thenReturn(CompletableFuture.completedFuture(ackResult)); - - AckMessageResponse response = consumerService.ackMessage(Context.current(), AckMessageRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .addEntries(AckMessageEntry.newBuilder() - .setMessageId("msgId") - .setReceiptHandle(createReceiptHandle().encode())) - .build()) - .get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - } - - @Test - public void testChangeInvisibleDuration() throws Exception { - Duration newDuration = Duration.newBuilder() - .setSeconds(3).build(); - ReceiptHandle receiptHandle = createReceiptHandle(); - ArgumentCaptor headerArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); - AckResult ackResult = new AckResult(); - ackResult.setStatus(AckStatus.OK); - ackResult.setExtraInfo(receiptHandle.encode()); - when(writeConsumerClient.changeInvisibleTimeAsync(any(), anyString(), anyString(), anyString(), headerArgumentCaptor.capture())) - .thenReturn(CompletableFuture.completedFuture(ackResult)); - when(topicRouteService.getBrokerAddr(anyString())).thenReturn("brokerAddr"); - - Settings clientSettings = createClientSettings(3); - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(clientSettings); - - ChangeInvisibleDurationResponse response = consumerService.changeInvisibleDuration(Context.current(), ChangeInvisibleDurationRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .setReceiptHandle(receiptHandle.encode()) - .setInvisibleDuration(newDuration) - .build()) - .get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals(receiptHandle.getOffset(), headerArgumentCaptor.getValue().getOffset().longValue()); - assertEquals(receiptHandle.encode(), headerArgumentCaptor.getValue().getExtraInfo()); - assertEquals(Durations.toMillis(newDuration), headerArgumentCaptor.getValue().getInvisibleTime().longValue()); - } - - private Settings createClientSettings(int maxDeliveryAttempts) { - return Settings.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(maxDeliveryAttempts) - .build()) - .setSubscription(Subscription.newBuilder() - .build()) - .build(); - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java deleted file mode 100644 index 231cb821e4..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultReadQueueSelectorTest.java +++ /dev/null @@ -1,89 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.ReceiveMessageRequest; -import io.grpc.Context; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.junit.Test; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.when; - -public class DefaultReadQueueSelectorTest extends BaseServiceTest { - - private final String brokerAddress = "127.0.0.1:10911"; - - @Override - public void beforeEach() throws Throwable { - } - - @Test - public void test() throws Exception { - SelectableMessageQueue messageQueue1 = new SelectableMessageQueue( - new MessageQueue("readBrokerTopicByName", "brokerName", 0), "brokerAddr1"); - SelectableMessageQueue messageQueue2 = new SelectableMessageQueue( - new MessageQueue("oneReadBroker", "brokerName", 0), "brokerAddr1"); - - when(topicRouteService.selectReadBrokerByName(eq("readBrokerTopicByName"), anyString())).thenReturn(messageQueue1); - when(topicRouteService.selectOneReadBroker(eq("oneReadBroker"), isNull())).thenReturn(messageQueue2); - - ReadQueueSelector readQueueSelector = new DefaultReadQueueSelector(topicRouteService); - - { - PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); - requestHeader.setTopic("readBrokerTopicByName"); - SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), - ReceiveMessageRequest.newBuilder() - .setMessageQueue(apache.rocketmq.v2.MessageQueue.newBuilder() - .setBroker(Broker.newBuilder() - .setName("brokerName") - .build()) - .build()) - .build(), - requestHeader); - assertSame(messageQueue1, messageQueue); - } - - { - PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); - requestHeader.setTopic("oneReadBroker"); - SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), - ReceiveMessageRequest.newBuilder() - .build(), - requestHeader); - assertSame(messageQueue2, messageQueue); - } - - { - PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); - requestHeader.setTopic("topic"); - SelectableMessageQueue messageQueue = readQueueSelector.select(Context.current(), - ReceiveMessageRequest.newBuilder() - .build(), - requestHeader); - assertNull(messageQueue); - } - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java deleted file mode 100644 index d5922a039d..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/DefaultWriteQueueSelectorTest.java +++ /dev/null @@ -1,94 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SystemProperties; -import com.google.protobuf.ByteString; -import io.grpc.Context; -import java.nio.charset.StandardCharsets; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.when; - -public class DefaultWriteQueueSelectorTest extends BaseServiceTest { - - @Override - public void beforeEach() throws Throwable { - SelectableMessageQueue queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectOrderQueue", 0), - "selectOrderQueueAddr"); - when(topicRouteService.selectOneWriteQueueByKey(anyString(), anyString())) - .thenReturn(queue); - - queue = new SelectableMessageQueue( - new MessageQueue("topic", "selectNormalQueue", 0), - "selectNormalQueueAddr"); - when(topicRouteService.selectOneWriteQueue(anyString(), isNull())) - .thenReturn(queue); - } - - @Test - public void selectWithShardingKey() { - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("msgId") - .setMessageGroup("key") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteService); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); - - assertEquals("selectOrderQueue", queue.getBrokerName()); - assertEquals("selectOrderQueueAddr", queue.getBrokerAddr()); - } - - @Test - public void selectNormalQueue() { - SendMessageRequest request = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build(); - WriteQueueSelector queueSelector = new DefaultWriteQueueSelector(this.topicRouteService); - SelectableMessageQueue queue = queueSelector.selectQueue(Context.current(), request); - - assertEquals("selectNormalQueue", queue.getBrokerName()); - assertEquals("selectNormalQueueAddr", queue.getBrokerAddr()); - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java deleted file mode 100644 index 870fb0b88a..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ForwardClientServiceTest.java +++ /dev/null @@ -1,142 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.ClientType; -//import apache.rocketmq.v2.FilterExpression; -//import apache.rocketmq.v2.FilterType; -//import apache.rocketmq.v2.HeartbeatRequest; -//import apache.rocketmq.v2.NotifyClientTerminationRequest; -//import apache.rocketmq.v2.Publishing; -//import apache.rocketmq.v2.Resource; -//import apache.rocketmq.v2.Settings; -//import apache.rocketmq.v2.Subscription; -//import apache.rocketmq.v2.SubscriptionEntry; -//import io.grpc.Context; -//import io.netty.channel.Channel; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.concurrent.Executors; -//import org.apache.rocketmq.broker.client.ClientChannelInfo; -//import org.apache.rocketmq.broker.client.ConsumerGroupInfo; -//import org.apache.rocketmq.common.consumer.ConsumeFromWhere; -//import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; -//import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.common.TelemetryCommandManager; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -//import org.apache.rocketmq.remoting.protocol.LanguageCode; -//import org.junit.Test; -// -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertNotNull; -//import static org.junit.Assert.assertNull; -//import static org.junit.Assert.assertTrue; -//import static org.mockito.ArgumentMatchers.anyString; -//import static org.mockito.Mockito.when; -// -//public class ForwardClientServiceTest extends BaseServiceTest { -// -// private ChannelManager channelManager = new ChannelManager(); -// private TelemetryCommandManager telemetryCommandManager = new TelemetryCommandManager(); -// private ForwardClientService clientService; -// -// @Override -// public void beforeEach() throws Throwable { -// clientService = new ForwardClientService( -// this.serviceManager, -// Executors.newSingleThreadScheduledExecutor(), -// this.channelManager, -// this.grpcClientManager, -// this.telemetryCommandManager); -// clientService.start(); -// } -// -// @Test -// public void testProducerHeartbeat() { -// Settings clientSettings = Settings.newBuilder() -// .setClientType(ClientType.PRODUCER) -// .setPublishing(Publishing.newBuilder() -// .addTopics(Resource.newBuilder() -// .setName("topic1") -// .build()) -// .addTopics(Resource.newBuilder() -// .setName("topic2") -// .build()) -// .build()) -// .build(); -// when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); -// -// clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder().build()); -// -// assertEquals(2, clientService.getProducerManager().getGroupChannelTable().size()); -// Channel channel = clientService.getProducerManager().findChannel(CLIENT_ID); -// assertNotNull(channel); -// assertTrue(channel instanceof GrpcClientChannel); -// -// clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder().build()); -// assertTrue(clientService.getProducerManager().getGroupChannelTable().isEmpty()); -// } -// -// @Test -// public void testConsumerHeartbeat() { -// List subscriptionEntryList = new ArrayList<>(); -// subscriptionEntryList.add(SubscriptionEntry.newBuilder() -// .setTopic(Resource.newBuilder() -// .setName("topic") -// .build()) -// .setExpression(FilterExpression.newBuilder() -// .setExpression("*") -// .setType(FilterType.TAG) -// .build()) -// .build()); -// -// Settings clientSettings = Settings.newBuilder() -// .setClientType(ClientType.PUSH_CONSUMER) -// .setSubscription(Subscription.newBuilder() -// .addAllSubscriptions(subscriptionEntryList) -// .build()) -// .build(); -// when(grpcClientManager.getClientSettings(anyString())).thenReturn(clientSettings); -// -// clientService.heartbeat(Context.current(), HeartbeatRequest.newBuilder() -// .setGroup(Resource.newBuilder() -// .setName("consumerGroup") -// .build()) -// .build()); -// -// ClientChannelInfo clientChannelInfo = clientService.getConsumerManager().findChannel("consumerGroup", CLIENT_ID); -// assertNotNull(clientChannelInfo); -// assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); -// assertEquals(CLIENT_ID, clientChannelInfo.getClientId()); -// assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); -// ConsumerGroupInfo consumerGroupInfo = clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup"); -// assertEquals(MessageModel.CLUSTERING, consumerGroupInfo.getMessageModel()); -// assertEquals(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, consumerGroupInfo.getConsumeFromWhere()); -// assertEquals(ConsumeType.CONSUME_PASSIVELY, consumerGroupInfo.getConsumeType()); -// assertEquals("TAG", consumerGroupInfo.getSubscriptionTable().get("topic").getExpressionType()); -// assertEquals("*", consumerGroupInfo.getSubscriptionTable().get("topic").getSubString()); -// -// -// clientService.notifyClientTermination(Context.current(), NotifyClientTerminationRequest.newBuilder() -// .setGroup(Resource.newBuilder() -// .setName("consumerGroup") -// .build()) -// .build()); -// assertNull(clientService.getConsumerManager().getConsumerGroupInfo("consumerGroup")); -// } -//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java deleted file mode 100644 index 68344d6899..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/ProducerServiceTest.java +++ /dev/null @@ -1,163 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SendMessageResponse; -import apache.rocketmq.v2.SystemProperties; -import com.google.protobuf.ByteString; -import io.grpc.Context; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.message.MessageQueue; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -import org.junit.Test; - -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.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - -public class ProducerServiceTest extends BaseServiceTest { - - private ProducerService producerService; - - private static final SendMessageRequest REQUEST = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build(); - - @Override - public void beforeEach() throws Throwable { - producerService = new ProducerService(this.serviceManager); - producerService.start(); - } - - @Test - public void testSendMessage() { - CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(any(), anyString(), anyString(), any(), any())) - .thenReturn(sendResultFuture); - sendResultFuture.complete(new SendResult(SendStatus.SEND_OK, "msgId", new MessageQueue(), - 1L, "txId", "offsetMsgId", "regionId")); - - producerService.setWriteQueueSelector((ctx, request) -> - new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); - - CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); - try { - SendMessageResponse response = future.get(); - - assertEquals(Code.OK, response.getStatus().getCode()); - assertEquals("msgId", response.getReceipts(0).getMessageId()); - } catch (Exception e) { - assertNull(e); - } - } - - @Test - public void testSendMessageNoQueueSelect() { - producerService.setWriteQueueSelector((ctx, request) -> null); - - CompletableFuture future = producerService.sendMessage(Context.current(), SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setTopic(Resource.newBuilder() - .setResourceNamespace("namespace") - .setName("topic") - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId("msgId") - .build()) - .setBody(ByteString.copyFrom("hello", StandardCharsets.UTF_8)) - .build()) - .build()); - - try { - SendMessageResponse response = future.get(); - assertNull(response); - } catch (Exception e) { - assertNotNull(e); - assertTrue(e instanceof ExecutionException); - assertTrue(e.getCause() instanceof ProxyException); - assertEquals(Code.FORBIDDEN, ((ProxyException) e.getCause()).getCode()); - } - } - - @Test - public void testSendMessageWithError() { - RuntimeException ex = new RuntimeException(); - - CompletableFuture sendResultFuture = new CompletableFuture<>(); - when(producerClient.sendMessage(any(), anyString(), anyString(), any(), any())) - .thenReturn(sendResultFuture); - sendResultFuture.completeExceptionally(ex); - - producerService.setWriteQueueSelector((ctx, request) -> - new SelectableMessageQueue(new MessageQueue("namespace%topic", "brokerName", 0), "brokerAddr")); - - CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); - - try { - SendMessageResponse response = future.get(); - assertNull(response); - } catch (Exception e) { - assertNotNull(e); - assertTrue(e instanceof ExecutionException); - assertSame(ex, e.getCause()); - } - } - - @Test - public void testSendMessageWithErrorThrow() { - RuntimeException ex = new RuntimeException(); - - producerService.setWriteQueueSelector((ctx, request) -> { - throw ex; - }); - producerService.setSendMessageHook((ctx, request, response, t) -> assertSame(ex, t)); - - CompletableFuture future = producerService.sendMessage(Context.current(), REQUEST); - - try { - SendMessageResponse response = future.get(); - assertNull(response); - } catch (Exception e) { - assertNotNull(e); - assertTrue(e instanceof ExecutionException); - assertSame(ex, e.getCause()); - } - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java deleted file mode 100644 index 7cea2646cf..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/RouteServiceTest.java +++ /dev/null @@ -1,251 +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.proxy.grpc.v2.service.cluster; - -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.Broker; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.MessageQueue; -import apache.rocketmq.v2.Permission; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.constant.PermName; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.route.BrokerData; -import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -public class RouteServiceTest extends BaseServiceTest { - private String brokerAddress = "127.0.0.1:10911"; - public static final String BROKER_NAME = "brokerName"; - public static final String NAMESPACE = "namespace"; - public static final String TOPIC = "topic"; - public static final Broker MOCK_BROKER = Broker.newBuilder().setName(BROKER_NAME).build(); - public static final Resource MOCK_TOPIC = Resource.newBuilder() - .setName(TOPIC) - .setResourceNamespace(NAMESPACE) - .build(); - - private static final Endpoints WITH_HOST_ENDPOINT = Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build(); - - private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() - .setAccessPoint(WITH_HOST_ENDPOINT) - .build(); - - - private static final Settings INVALID_HOST_SETTINGS = Settings.newBuilder() - .setAccessPoint(Endpoints.getDefaultInstance()) - .build(); - - private RouteService routeService; - - @Override - public void beforeEach() throws Exception { - TopicRouteData routeData = new TopicRouteData(); - - List brokerDataList = new ArrayList<>(); - BrokerData brokerData = new BrokerData(); - brokerData.setCluster("cluster"); - brokerData.setBrokerName("brokerName"); - HashMap brokerAddrs = new HashMap() {{ - put(0L, brokerAddress); - }}; - brokerData.setBrokerAddrs(brokerAddrs); - brokerDataList.add(brokerData); - - List queueDataList = new ArrayList<>(); - QueueData queueData = new QueueData(); - queueData.setPerm(6); - queueData.setWriteQueueNums(8); - queueData.setReadQueueNums(8); - queueData.setBrokerName("brokerName"); - queueDataList.add(queueData); - - routeData.setBrokerDatas(brokerDataList); - routeData.setQueueDatas(queueDataList); - - MessageQueueView messageQueueView = new MessageQueueView("topic", routeData); - when(this.topicRouteService.getAllMessageQueueView("topic")).thenReturn(messageQueueView); - - when(this.topicRouteService.getAllMessageQueueView("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); - - routeService = new RouteService(this.serviceManager, this.grpcClientManager); - routeService.start(); - } - - @Test - public void testGenPartitionFromQueueData() throws Exception { - // test queueData with 8 read queues, 8 write queues, and rw permission, expect 8 rw queues. - QueueData queueDataWith8R8WPermRW = mockQueueData(8, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R8WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermRW, MOCK_TOPIC, MOCK_BROKER); - assertThat(partitionWith8R8WPermRW.size()).isEqualTo(8); - assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(8); - assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); - assertThat(partitionWith8R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); - - // test queueData with 8 read queues, 8 write queues, and read only permission, expect 8 read only queues. - QueueData queueDataWith8R8WPermR = mockQueueData(8, 8, PermName.PERM_READ); - List partitionWith8R8WPermR = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermR, MOCK_TOPIC, MOCK_BROKER); - assertThat(partitionWith8R8WPermR.size()).isEqualTo(8); - assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); - assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); - assertThat(partitionWith8R8WPermR.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); - - // test queueData with 8 read queues, 8 write queues, and write only permission, expect 8 write only queues. - QueueData queueDataWith8R8WPermW = mockQueueData(8, 8, PermName.PERM_WRITE); - List partitionWith8R8WPermW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R8WPermW, MOCK_TOPIC, MOCK_BROKER); - assertThat(partitionWith8R8WPermW.size()).isEqualTo(8); - assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(8); - assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); - assertThat(partitionWith8R8WPermW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); - - // test queueData with 8 read queues, 0 write queues, and rw permission, expect 8 read only queues. - QueueData queueDataWith8R0WPermRW = mockQueueData(8, 0, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith8R0WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith8R0WPermRW, MOCK_TOPIC, MOCK_BROKER); - assertThat(partitionWith8R0WPermRW.size()).isEqualTo(8); - assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(8); - assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(0); - assertThat(partitionWith8R0WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(0); - - // test queueData with 4 read queues, 8 write queues, and rw permission, expect 4 rw queues and 4 write only queues. - QueueData queueDataWith4R8WPermRW = mockQueueData(4, 8, PermName.PERM_READ | PermName.PERM_WRITE); - List partitionWith4R8WPermRW = GrpcConverter.genMessageQueueFromQueueData(queueDataWith4R8WPermRW, MOCK_TOPIC, MOCK_BROKER); - assertThat(partitionWith4R8WPermRW.size()).isEqualTo(8); - assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.WRITE).count()).isEqualTo(4); - assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ_WRITE).count()).isEqualTo(4); - assertThat(partitionWith4R8WPermRW.stream().filter(a -> a.getPermission() == Permission.READ).count()).isEqualTo(0); - - } - - private QueueData mockQueueData(int r, int w, int perm) { - QueueData queueData = new QueueData(); - queueData.setBrokerName(BROKER_NAME); - queueData.setReadQueueNums(r); - queueData.setWriteQueueNums(w); - queueData.setPerm(perm); - return queueData; - } - - @Test - public void testQueryRouteWithInvalidEndpoints() throws Exception { - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .build()); - - QueryRouteResponse response = future.get(); - assertEquals(Code.ILLEGAL_ACCESS_POINT.getNumber(), response.getStatus().getCode().getNumber()); - } - - @Test - public void testQueryRoute() throws Exception { - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setEndpoints(WITH_HOST_ENDPOINT) - .build()); - - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(8, response.getMessageQueuesCount()); - assertEquals("host", response.getMessageQueues(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } - - @Test - public void testQueryRouteWhenTopicNotExist() throws Exception { - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("notExistTopic") - .build()) - .build()); - - QueryRouteResponse response = future.get(); - assertEquals(Code.TOPIC_NOT_FOUND.getNumber(), response.getStatus().getCode().getNumber()); - } - - @Test - public void testQueryAssignmentInvalidEndpoints() throws Exception { - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(INVALID_HOST_SETTINGS); - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setTopic( - Resource.newBuilder() - .setName("topic") - .build() - ) - .build()); - - QueryAssignmentResponse response = future.get(); - assertEquals(Code.ILLEGAL_ACCESS_POINT.getNumber(), response.getStatus().getCode().getNumber()); - } - - @Test - public void testQueryAssignment() throws Exception { - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setEndpoints(WITH_HOST_ENDPOINT) - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build()); - - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); - assertEquals("host", response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); - } - -} diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java deleted file mode 100644 index f8f647cb01..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/cluster/TransactionServiceTest.java +++ /dev/null @@ -1,104 +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.proxy.grpc.v2.service.cluster; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.EndTransactionRequest; -//import apache.rocketmq.v2.EndTransactionResponse; -//import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; -//import apache.rocketmq.v2.TelemetryCommand; -//import io.grpc.Context; -//import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.service.transaction.TransactionId; -//import org.apache.rocketmq.proxy.service.transaction.TransactionStateCheckRequest; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.channel.GrpcClientChannel; -//import org.apache.rocketmq.remoting.common.RemotingHelper; -//import org.assertj.core.util.Lists; -//import org.junit.Test; -//import org.mockito.ArgumentCaptor; -//import org.mockito.Mock; -// -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertTrue; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.anyString; -//import static org.mockito.Mockito.doNothing; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.when; -// -//public class TransactionServiceTest extends BaseServiceTest { -// -// private TransactionService transactionService; -// @Mock -// private ChannelManager channelManager; -// -// @Override -// public void beforeEach() throws Throwable { -// transactionService = new TransactionService(this.serviceManager, this.channelManager); -// } -// -// @Test -// public void testCheckTransactionState() { -// GrpcClientChannel channel = mock(GrpcClientChannel.class); -// -// when(channelManager.getClientIdList(anyString())).thenReturn(Lists.newArrayList("clientId")); -// when(channelManager.getChannel(anyString(), any())).thenReturn(channel); -// ArgumentCaptor flushDataCaptor = ArgumentCaptor.forClass(Object.class); -// when(channel.writeAndFlush(flushDataCaptor.capture())).thenReturn(null); -// -// TransactionId transactionId = TransactionId.genByBrokerTransactionId( -// RemotingHelper.string2SocketAddress("127.0.0.1:8080"), -// "71F99B78B6E261357FA259CCA6456118", 1234, 5678); -// transactionService.checkTransactionState(new TransactionStateCheckRequest( -// "group", -// 1L, -// 2L, -// "msgId", -// transactionId, -// "brokerName", -// createMessageExt("msgId", "msgId") -// )); -// -// Object flushData = flushDataCaptor.getValue(); -// assertTrue(flushData instanceof TelemetryCommand); -// TelemetryCommand response = (TelemetryCommand) flushData; -// RecoverOrphanedTransactionCommand command = response.getRecoverOrphanedTransactionCommand(); -// assertEquals(transactionId.getProxyTransactionId(), command.getTransactionId()); -// assertEquals("brokerName", command.getMessageQueue().getBroker().getName()); -// } -// -// @Test -// public void testEndTransaction() throws Exception { -// TransactionId transactionId = TransactionId.genByBrokerTransactionId( -// RemotingHelper.string2SocketAddress("127.0.0.1:8080"), -// "71F99B78B6E261357FA259CCA6456118", 1234, 5678); -// ArgumentCaptor brokerAddrCaptor = ArgumentCaptor.forClass(String.class); -// ArgumentCaptor headerCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); -// doNothing().when(producerClient) -// .endTransaction(any(), brokerAddrCaptor.capture(), headerCaptor.capture()); -// -// EndTransactionResponse response = transactionService.endTransaction(Context.current(), EndTransactionRequest.newBuilder() -// .setTransactionId(transactionId.getProxyTransactionId()) -// .build() -// ).get(); -// -// assertEquals(Code.OK, response.getStatus().getCode()); -// assertEquals(transactionId.getBrokerTransactionId(), headerCaptor.getValue().getTransactionId()); -// assertEquals("127.0.0.1:8080", brokerAddrCaptor.getValue()); -// } -//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java deleted file mode 100644 index 4ef59dcdc1..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalPopMessageResultFilterTest.java +++ /dev/null @@ -1,135 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.FilterExpression; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.Settings; -//import io.grpc.Context; -//import java.net.InetSocketAddress; -//import java.nio.charset.StandardCharsets; -//import java.util.ArrayList; -//import java.util.List; -//import org.apache.rocketmq.broker.BrokerController; -//import org.apache.rocketmq.broker.processor.AckMessageProcessor; -//import org.apache.rocketmq.broker.processor.SendMessageProcessor; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.message.MessageConst; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.common.protocol.RequestCode; -//import org.apache.rocketmq.common.protocol.ResponseCode; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.channel.SimpleChannel; -//import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -//import org.apache.rocketmq.proxy.grpc.v2.service.GrpcClientManager; -//import org.apache.rocketmq.remoting.exception.RemotingCommandException; -//import org.apache.rocketmq.remoting.protocol.RemotingCommand; -//import org.junit.Test; -//import org.junit.runner.RunWith; -//import org.mockito.Mock; -//import org.mockito.Mockito; -//import org.mockito.junit.MockitoJUnitRunner; -// -//@RunWith(MockitoJUnitRunner.class) -//public class LocalPopMessageResultFilterTest extends InitConfigAndLoggerTest { -// @Mock -// private ChannelManager channelManagerMock; -// @Mock -// private BrokerController brokerControllerMock; -// @Mock -// private GrpcClientManager grpcClientManagerMock; -// @Mock -// private AckMessageProcessor ackMessageProcessorMock; -// @Mock -// private SendMessageProcessor sendMessageProcessorMock; -// -// private String topic = "topic"; -// -// @Test -// public void testFilterMessageWhenNotMatch() throws RemotingCommandException { -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); -// Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); -// Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); -// Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); -// Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); -// List messageExtList = new ArrayList<>(); -// MessageExt messageExt = new MessageExt(); -// messageExt.setTopic(topic); -// messageExt.setQueueOffset(0L); -// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); -// messageExt.putUserProperty("key", "value"); -// messageExt.setTags("b"); -// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() -// .startOffset(0L) -// .retrieveTime(0L) -// .invisibleTime(1000L) -// .nextVisibleTime(1000L) -// .reviveQueueId(0) -// .topicType("0") -// .brokerName("brokerName") -// .queueId(0) -// .offset(0L) -// .build().encode()); -// messageExtList.add(messageExt); -// LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); -// localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() -// .setFilterExpression(FilterExpression.newBuilder() -// .setExpression("a").build()).build(), messageExtList); -// Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); -// } -// -// @Test -// public void testFilterMessageWhenDLQ() throws RemotingCommandException { -// RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); -// Mockito.when(channelManagerMock.createChannel(Mockito.any(Context.class))).thenReturn(new SimpleChannel(null, null, null, 0)); -// Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); -// Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); -// Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); -// Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(), Mockito.any())).thenReturn(remotingCommand); -// Mockito.when(grpcClientManagerMock.getClientSettings(Mockito.any(Context.class))).thenReturn(Settings.newBuilder().build()); -// List messageExtList = new ArrayList<>(); -// MessageExt messageExt = new MessageExt(); -// messageExt.setTopic(topic); -// messageExt.setQueueOffset(0L); -// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); -// messageExt.putUserProperty("key", "value"); -// messageExt.setTags("a"); -// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() -// .startOffset(0L) -// .retrieveTime(0L) -// .invisibleTime(1000L) -// .nextVisibleTime(1000L) -// .reviveQueueId(0) -// .topicType("0") -// .brokerName("brokerName") -// .queueId(0) -// .offset(0L) -// .build().encode()); -// messageExtList.add(messageExt); -// LocalReceiveMessageResultFilter localReceiveMessageResultFilter = new LocalReceiveMessageResultFilter(channelManagerMock, brokerControllerMock, grpcClientManagerMock); -// localReceiveMessageResultFilter.filterMessage(Context.current(), ReceiveMessageRequest.newBuilder() -// .setFilterExpression(FilterExpression.newBuilder() -// .setExpression("a").build()).build(), messageExtList); -// Mockito.verify(sendMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK)); -// Mockito.verify(ackMessageProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.argThat(r -> r.getCode() == RequestCode.ACK_MESSAGE)); -// } -//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java deleted file mode 100644 index d9ec53eb43..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalReceiveMessageResponseStreamWriterTest.java +++ /dev/null @@ -1,170 +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.proxy.grpc.v2.service.local; -// -//import apache.rocketmq.v2.Code; -//import apache.rocketmq.v2.Message; -//import apache.rocketmq.v2.ReceiveMessageRequest; -//import apache.rocketmq.v2.ReceiveMessageResponse; -//import io.grpc.Context; -//import io.grpc.Status; -//import io.grpc.StatusRuntimeException; -//import io.grpc.stub.ServerCallStreamObserver; -//import java.net.InetSocketAddress; -//import java.nio.charset.StandardCharsets; -//import java.util.ArrayList; -//import java.util.List; -//import java.util.concurrent.atomic.AtomicInteger; -//import org.apache.rocketmq.broker.BrokerController; -//import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; -//import org.apache.rocketmq.client.consumer.PopStatus; -//import org.apache.rocketmq.common.consumer.ReceiptHandle; -//import org.apache.rocketmq.common.message.MessageConst; -//import org.apache.rocketmq.common.message.MessageExt; -//import org.apache.rocketmq.proxy.grpc.v2.common.ChannelManager; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.GrpcConverter; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ProxyException; -//import org.apache.rocketmq.proxy.grpc.v2.adapter.ResponseBuilder; -//import org.apache.rocketmq.proxy.grpc.v2.service.ReceiveMessageResultFilter; -//import org.apache.rocketmq.remoting.exception.RemotingCommandException; -//import org.junit.Before; -//import org.junit.Test; -//import org.junit.runner.RunWith; -//import org.mockito.ArgumentCaptor; -//import org.mockito.Mock; -//import org.mockito.Mockito; -//import org.mockito.invocation.InvocationOnMock; -//import org.mockito.junit.MockitoJUnitRunner; -//import org.mockito.stubbing.Answer; -// -//import static org.assertj.core.api.Assertions.assertThat; -// -//@RunWith(MockitoJUnitRunner.class) -//public class LocalReceiveMessageResponseStreamWriterTest { -// @Mock -// private ServerCallStreamObserver streamObserverMock; -// @Mock -// private ChannelManager channelManagerMock; -// @Mock -// private BrokerController brokerControllerMock; -// @Mock -// private ReceiveMessageResultFilter receiveMessageResultFilterMock; -// @Mock -// private ChangeInvisibleTimeProcessor changeInvisibleTimeProcessorMock; -// -// private LocalReceiveMessageResponseStreamWriter localReceiveMessageResponseStreamWriter; -// -// @Before -// public void setup() { -// Mockito.when(receiveMessageResultFilterMock.filterMessage(Mockito.any(), Mockito.any(), Mockito.anyList())).thenAnswer((Answer>) invocation -> { -// List messageList = new ArrayList<>(); -// List messageExtList = invocation.getArgument(2); -// for (MessageExt messageExt : messageExtList) { -// messageList.add(GrpcConverter.buildMessage(messageExt)); -// } -// return messageList; -// }); -// localReceiveMessageResponseStreamWriter -// = new LocalReceiveMessageResponseStreamWriter(streamObserverMock, null, channelManagerMock, brokerControllerMock, receiveMessageResultFilterMock); -// } -// -// @Test -// public void testWrite() { -// MessageExt messageExt = new MessageExt(); -// messageExt.setTopic("topic"); -// messageExt.setQueueOffset(0L); -// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); -// messageExt.putUserProperty("key", "value"); -// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() -// .startOffset(0L) -// .retrieveTime(0L) -// .invisibleTime(1000L) -// .nextVisibleTime(1000L) -// .reviveQueueId(0) -// .topicType("0") -// .brokerName("brokerName") -// .queueId(0) -// .offset(0L) -// .build().encode()); -// messageExt.putUserProperty("key", "value"); -// List messageExtList = new ArrayList<>(); -// messageExtList.add(messageExt); -// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); -// ArgumentCaptor argument = ArgumentCaptor.forClass(ReceiveMessageResponse.class); -// Mockito.verify(streamObserverMock, Mockito.times(2)).onNext(argument.capture()); -// assertThat(argument.getAllValues().get(0)).isEqualTo(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build()); -// assertThat(argument.getAllValues().get(1)).isEqualTo(ReceiveMessageResponse.newBuilder() -// .setMessage(GrpcConverter.buildMessage(messageExt)).build()); -// } -// -// @Test -// public void testWriteWhenNoMessage() { -// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, new ArrayList<>()); -// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, "no new message")).build())); -// } -// -// @Test -// public void testWriteWhenCancel() throws RemotingCommandException { -// AtomicInteger onNextCallTimes = new AtomicInteger(0); -// Mockito.doAnswer(mock -> { -// if (onNextCallTimes.get() <=0) { -// onNextCallTimes.incrementAndGet(); -// return null; -// } -// throw new StatusRuntimeException(Status.CANCELLED); -// }).when(streamObserverMock).onNext(Mockito.any()); -// Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); -// MessageExt messageExt = new MessageExt(); -// messageExt.setTopic("topic"); -// messageExt.setQueueOffset(0L); -// messageExt.setBornHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setStoreHost(new InetSocketAddress("127.0.0.1", 10911)); -// messageExt.setBody("body".getBytes(StandardCharsets.UTF_8)); -// messageExt.putUserProperty("key", "value"); -// messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, ReceiptHandle.builder() -// .startOffset(0L) -// .retrieveTime(0L) -// .invisibleTime(1000L) -// .nextVisibleTime(1000L) -// .reviveQueueId(0) -// .topicType("0") -// .brokerName("brokerName") -// .queueId(0) -// .offset(0L) -// .build().encode()); -// messageExt.putUserProperty("key", "value"); -// List messageExtList = new ArrayList<>(); -// messageExtList.add(messageExt); -// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), PopStatus.FOUND, messageExtList); -// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())).build())); -// Mockito.verify(changeInvisibleTimeProcessorMock, Mockito.times(1)).processRequest(Mockito.any(), Mockito.any()); -// } -// -// @Test -// public void testWriteError() { -// String info = "error"; -// localReceiveMessageResponseStreamWriter.write(Context.current(), ReceiveMessageRequest.newBuilder().build(), new ProxyException(Code.ILLEGAL_MESSAGE, info)); -// Mockito.verify(streamObserverMock, Mockito.times(1)).onNext(Mockito.eq(ReceiveMessageResponse.newBuilder() -// .setStatus(ResponseBuilder.buildStatus(Code.ILLEGAL_MESSAGE, info)).build())); -// } -//} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java deleted file mode 100644 index 4e6a871928..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/LocalWriteQueueSelectorTest.java +++ /dev/null @@ -1,78 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Message; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.SendMessageRequest; -import apache.rocketmq.v2.SystemProperties; -import io.grpc.Context; -import org.apache.rocketmq.broker.topic.TopicConfigManager; -import org.apache.rocketmq.common.TopicConfig; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LocalWriteQueueSelectorTest { - private LocalWriteQueueSelector localWriteQueueSelector; - private String topic = "test-topic"; - private String brokerName = "broker"; - private int writeQueueId = 8; - private String messageGroup = "message-group"; - - @Before - public void setup() { - TopicConfigManager topicConfigManager = Mockito.mock(TopicConfigManager.class); - TopicConfig topicConfig = new TopicConfig(topic, writeQueueId, writeQueueId); - Mockito.when(topicConfigManager.selectTopicConfig(topic)).thenReturn(topicConfig); - localWriteQueueSelector = new LocalWriteQueueSelector(brokerName, topicConfigManager, null); - } - - @Test - public void testSelectQueueWithNormalMessage() { - SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder().setTopic(Resource.newBuilder().setName(topic).build())) - .build(); - SelectableMessageQueue selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); - assertThat(selectableMessageQueue.getBrokerName()).isEqualTo(brokerName); - assertThat(selectableMessageQueue.getTopic()).isEqualTo(topic); - int selectQueueId = selectableMessageQueue.getQueueId(); - selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); - assertThat(selectableMessageQueue.getQueueId()).isEqualTo((selectQueueId + 1) % writeQueueId); - } - - @Test - public void testSelectQueueWithFifoMessage() { - SendMessageRequest sendMessageRequest = SendMessageRequest.newBuilder() - .addMessages(Message.newBuilder() - .setSystemProperties(SystemProperties.newBuilder() - .setMessageGroup(messageGroup) - .build()) - .setTopic(Resource.newBuilder().setName(topic).build())) - .build(); - SelectableMessageQueue selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); - assertThat(selectableMessageQueue.getBrokerName()).isEqualTo(brokerName); - assertThat(selectableMessageQueue.getTopic()).isEqualTo(topic); - int selectQueueId = selectableMessageQueue.getQueueId(); - selectableMessageQueue = localWriteQueueSelector.selectQueue(Context.current(), sendMessageRequest); - assertThat(selectableMessageQueue.getQueueId()).isEqualTo(selectQueueId); - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java b/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java deleted file mode 100644 index d7c8bee76f..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/grpc/v2/service/local/RouteServiceTest.java +++ /dev/null @@ -1,132 +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.proxy.grpc.v2.service.local; - -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; -import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; -import apache.rocketmq.v2.QueryAssignmentRequest; -import apache.rocketmq.v2.QueryAssignmentResponse; -import apache.rocketmq.v2.QueryRouteRequest; -import apache.rocketmq.v2.QueryRouteResponse; -import apache.rocketmq.v2.Resource; -import apache.rocketmq.v2.Settings; -import com.google.common.net.HostAndPort; -import io.grpc.Context; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.client.exception.MQClientException; -import org.apache.rocketmq.common.protocol.ResponseCode; -import org.apache.rocketmq.common.protocol.route.BrokerData; -import org.apache.rocketmq.common.protocol.route.QueueData; -import org.apache.rocketmq.common.protocol.route.TopicRouteData; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.grpc.v2.service.cluster.BaseServiceTest; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -public class RouteServiceTest extends BaseServiceTest { - private String brokerAddress = "127.0.0.1:10911"; - private static final Settings WITH_HOST_SETTINGS = Settings.newBuilder() - .setAccessPoint(Endpoints.newBuilder() - .addAddresses(Address.newBuilder() - .setPort(80) - .setHost("host") - .build()) - .setScheme(AddressScheme.DOMAIN_NAME) - .build()) - .build(); - - @Test - public void testLocalModeQueryRoute() throws Exception { - RouteService routeService = new RouteService(this.serviceManager, this.grpcClientManager); - routeService.start(); - - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryRoute(Context.current(), QueryRouteRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .build()); - QueryRouteResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(8, response.getMessageQueuesCount()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getMessageQueues(0).getBroker() - .getEndpoints().getAddresses(0).getHost()); - } - - @Test - public void testLocalModeQueryAssignment() throws Exception { - RouteService routeService = new RouteService(this.serviceManager, this.grpcClientManager); - routeService.start(); - - when(grpcClientManager.getClientSettings(any(Context.class))).thenReturn(WITH_HOST_SETTINGS); - - CompletableFuture future = routeService.queryAssignment(Context.current(), QueryAssignmentRequest.newBuilder() - .setTopic(Resource.newBuilder() - .setName("topic") - .build()) - .setGroup(Resource.newBuilder() - .setName("group") - .build()) - .build()); - - QueryAssignmentResponse response = future.get(); - assertEquals(Code.OK.getNumber(), response.getStatus().getCode().getNumber()); - assertEquals(1, response.getAssignmentsCount()); - assertEquals("brokerName", response.getAssignments(0).getMessageQueue().getBroker().getName()); - assertEquals(HostAndPort.fromString(brokerAddress).getHost(), response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getHost()); - } - - @Override public void beforeEach() throws Throwable { - TopicRouteData routeData = new TopicRouteData(); - - List brokerDataList = new ArrayList<>(); - BrokerData brokerData = new BrokerData(); - brokerData.setCluster("cluster"); - brokerData.setBrokerName("brokerName"); - HashMap brokerAddrs = new HashMap() {{ - put(0L, brokerAddress); - }}; - brokerData.setBrokerAddrs(brokerAddrs); - brokerDataList.add(brokerData); - - List queueDataList = new ArrayList<>(); - QueueData queueData = new QueueData(); - queueData.setPerm(6); - queueData.setWriteQueueNums(8); - queueData.setReadQueueNums(8); - queueData.setBrokerName("brokerName"); - queueDataList.add(queueData); - - routeData.setBrokerDatas(brokerDataList); - routeData.setQueueDatas(queueDataList); - - MessageQueueView messageQueueView = new MessageQueueView("topic", routeData); - when(this.topicRouteService.getAllMessageQueueView("topic")).thenReturn(messageQueueView); - - when(this.topicRouteService.getAllMessageQueueView("notExistTopic")).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); - } -} \ No newline at end of file diff --git a/proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java b/proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java deleted file mode 100644 index b6b81eb2d8..0000000000 --- a/proxy/src/test/resources/backup/test/proxy/service/ForwardClientManagerTest.java +++ /dev/null @@ -1,55 +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.proxy.service; - -import org.apache.rocketmq.proxy.service.transaction.TransactionStateChecker; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; -import org.junit.Test; -import org.mockito.Mockito; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ForwardClientManagerTest extends InitConfigAndLoggerTest { - - @Test - public void testConnectorManager() throws Exception { - ConfigurationManager.getProxyConfig().setNameSrvAddr("127.0.0.1:9876"); - - TransactionStateChecker mockedTransactionStateChecker = Mockito.mock(TransactionStateChecker.class); - ServiceManager serviceManager = new ServiceManager(mockedTransactionStateChecker); - serviceManager.start(); - - assertThat(serviceManager.getDefaultForwardClient()).isNotNull(); - assertThat(serviceManager.getDefaultForwardClient().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getDefaultForwardClientNum()); - - assertThat(serviceManager.getForwardProducer()).isNotNull(); - assertThat(serviceManager.getForwardProducer().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getForwardProducerNum()); - - assertThat(serviceManager.getForwardReadConsumer()).isNotNull(); - assertThat(serviceManager.getForwardReadConsumer().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); - - assertThat(serviceManager.getForwardWriteConsumer()).isNotNull(); - assertThat(serviceManager.getForwardWriteConsumer().getClientNum()) - .isEqualTo(ConfigurationManager.getProxyConfig().getForwardConsumerNum()); - - } -} From f334ca18df26c91c430f8645a3cea5610cd17971 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 20 May 2022 14:45:23 +0800 Subject: [PATCH 194/338] [ISSUE #3949] Fix batch sendMessageAsync --- .../rocketmq/proxy/service/mqclient/MQClientAPIExt.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 8826c188a1..c45db7fa37 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -190,8 +190,10 @@ public class MQClientAPIExt extends MQClientAPIImpl { requestHeader.setBatch(true); MessageBatch msgBatch = MessageBatch.generateFromList(msgList); MessageClientIDSetter.setUniqID(msgBatch); - msgBatch.setBody(msgBatch.encode()); + byte[] body = msgBatch.encode(); + msgBatch.setBody(body); + request.setBody(body); this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { RemotingCommand response = responseFuture.getResponseCommand(); if (response != null) { From 1a8c54bf48842220528eb4d231bcc2200b7c1885 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 23 May 2022 10:58:16 +0800 Subject: [PATCH 195/338] [ISSUE #3949] Add sendMessage in LocalMessageService --- pom.xml | 2 +- .../proxy/common/ProxyExceptionCode.java | 3 +- .../rocketmq/proxy/config/ProxyConfig.java | 9 + .../grpc/v2/common/GrpcProxyException.java | 2 + .../proxy/service/LocalServiceManager.java | 29 ++- .../proxy/service/channel/ChannelManager.java | 92 ++++++++ .../service/channel/InvocationChannel.java | 80 +++++++ .../service/channel/InvocationContext.java | 43 ++++ .../channel/InvocationContextInterface.java} | 10 +- .../proxy/service/channel/SimpleChannel.java | 23 ++ .../service/message/LocalMessageService.java | 92 +++++++- .../message/LocalMessageServiceTest.java | 208 ++++++++++++++++++ 12 files changed, 580 insertions(+), 13 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationChannel.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContext.java rename proxy/src/main/java/org/apache/rocketmq/proxy/{common/Cleaner.java => service/channel/InvocationContextInterface.java} (76%) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java diff --git a/pom.xml b/pom.xml index 9caa47358d..b29d63409b 100644 --- a/pom.xml +++ b/pom.xml @@ -434,7 +434,7 @@ org.assertj assertj-core - 2.6.0 + 3.22.0 test diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index ae056b2168..a297e50aed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -20,5 +20,6 @@ public enum ProxyExceptionCode { FORBIDDEN, RECEIPT_HANDLE_EXPIRED, INVALID_BROKER_NAME, - INVALID_RECEIPT_HANDLE + INVALID_RECEIPT_HANDLE, + ILLEGAL_MESSAGE, } 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 2127a6c0f7..6bf4ecf653 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 @@ -56,6 +56,7 @@ public class ProxyConfig { private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; private int channelExpiredInSeconds = 60; + private int contextExpiredInSeconds = 30; private int rocketmqMQClientNum = 6; @@ -251,6 +252,14 @@ public class ProxyConfig { this.channelExpiredInSeconds = channelExpiredInSeconds; } + public int getContextExpiredInSeconds() { + return contextExpiredInSeconds; + } + + public void setContextExpiredInSeconds(int contextExpiredInSeconds) { + this.contextExpiredInSeconds = contextExpiredInSeconds; + } + public int getRocketmqMQClientNum() { return rocketmqMQClientNum; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index 702ca2c75d..7cd5f5a43d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -31,8 +31,10 @@ public class GrpcProxyException extends RuntimeException { static { CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.INVALID_RECEIPT_HANDLE); + CODE_MAPPING.put(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, Code.INVALID_RECEIPT_HANDLE); CODE_MAPPING.put(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, Code.RECEIPT_HANDLE_EXPIRED); CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); + CODE_MAPPING.put(ProxyExceptionCode.ILLEGAL_MESSAGE, Code.ILLEGAL_MESSAGE); } public GrpcProxyException(Code code, String message) { 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 c55d0acb87..42c9e249d2 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 @@ -17,18 +17,23 @@ 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; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.service.channel.ChannelManager; import org.apache.rocketmq.proxy.service.message.LocalMessageService; import org.apache.rocketmq.proxy.service.message.MessageService; -import org.apache.rocketmq.proxy.service.relay.LocalProxyRelayService; -import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.metadata.LocalMetadataService; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.mqclient.DoNothingClientRemotingProcessor; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.relay.LocalProxyRelayService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.LocalTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.LocalTransactionService; @@ -45,16 +50,21 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser private final MetadataService metadataService; private final MQClientAPIFactory mqClientAPIFactory; + private final ChannelManager channelManager; + + private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryImpl("LocalServiceManagerScheduledThread")); public LocalServiceManager(BrokerController brokerController, RPCHook rpcHook) { this.brokerController = brokerController; - this.messageService = new LocalMessageService(brokerController, rpcHook); + this.channelManager = new ChannelManager(); + this.messageService = new LocalMessageService(brokerController, channelManager, rpcHook); this.mqClientAPIFactory = new MQClientAPIFactory( "TopicRouteServiceClient_", 1, new DoNothingClientRemotingProcessor(null), rpcHook, - Executors.newSingleThreadScheduledExecutor() + scheduledExecutorService ); this.topicRouteService = new LocalTopicRouteService(brokerController, mqClientAPIFactory); this.transactionService = new LocalTransactionService(); @@ -66,6 +76,7 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser protected void init() { this.appendStartAndShutdown(this.mqClientAPIFactory); this.appendStartAndShutdown(this.topicRouteService); + this.appendStartAndShutdown(new LocalServiceManagerStartAndShutdown()); } @Override @@ -102,4 +113,14 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser public MetadataService getMetadataService() { return this.metadataService; } + + private class LocalServiceManagerStartAndShutdown implements StartAndShutdown { + @Override public void start() throws Exception { + LocalServiceManager.this.scheduledExecutorService.scheduleWithFixedDelay(channelManager::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); + } + + @Override public void shutdown() throws Exception { + LocalServiceManager.this.scheduledExecutorService.shutdown(); + } + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java new file mode 100644 index 0000000000..f4b4e1896e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java @@ -0,0 +1,92 @@ +/* + * 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.service.channel; + +import com.google.common.base.Strings; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.proxy.common.ContextVariable; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ChannelManager { + private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private final ConcurrentMap clientIdChannelMap = new ConcurrentHashMap<>(); + + public SimpleChannel createChannel(ProxyContext context) { + final String clientId = anonymousChannelId(context); + if (Strings.isNullOrEmpty(clientId)) { + log.warn("ClientId is unexpected null or empty"); + return createChannelInner(context); + } + + SimpleChannel channel = clientIdChannelMap.computeIfAbsent(clientId, k -> createChannelInner(context)); + channel.updateLastAccessTime(); + return channel; + } + + public SimpleChannel createInvocationChannel(ProxyContext context) { + final String clientId = anonymousChannelId(InvocationChannel.class.getName(), context); + final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); + final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + if (Strings.isNullOrEmpty(clientId)) { + log.warn("ClientId is unexpected null or empty"); + return new InvocationChannel(clientHost, localAddress); + } + + SimpleChannel channel = clientIdChannelMap.computeIfAbsent(clientId, k -> new InvocationChannel(clientHost, localAddress)); + channel.updateLastAccessTime(); + return channel; + } + + private String anonymousChannelId(ProxyContext context) { + final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); + final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + return clientHost + "@" + localAddress; + } + + private String anonymousChannelId(String key, ProxyContext context) { + final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); + final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + return key + "@" + clientHost + "@" + localAddress; + } + + private SimpleChannel createChannelInner(ProxyContext context) { + return new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + } + + public void scanAndCleanChannels() { + try { + Iterator> iterator = clientIdChannelMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (!entry.getValue().isActive()) { + iterator.remove(); + } else { + entry.getValue().clearExpireContext(); + } + } + } catch (Throwable e) { + log.error("Unexpected exception", e); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationChannel.java new file mode 100644 index 0000000000..00e8cea99c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationChannel.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.channel; + +import io.netty.channel.ChannelFuture; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class InvocationChannel extends SimpleChannel { + protected final ConcurrentMap inFlightRequestMap; + + public InvocationChannel(String remoteAddress, String localAddress) { + super(remoteAddress, localAddress); + this.inFlightRequestMap = new ConcurrentHashMap<>(); + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + if (msg instanceof RemotingCommand) { + RemotingCommand responseCommand = (RemotingCommand) msg; + InvocationContextInterface context = inFlightRequestMap.remove(responseCommand.getOpaque()); + if (null != context) { + context.handle(responseCommand); + } + inFlightRequestMap.remove(responseCommand.getOpaque()); + } + return super.writeAndFlush(msg); + } + + @Override + public boolean isWritable() { + return inFlightRequestMap.size() > 0; + } + + @Override + public void registerInvocationContext(int opaque, InvocationContextInterface context) { + inFlightRequestMap.put(opaque, context); + } + + @Override + public void eraseInvocationContext(int opaque) { + inFlightRequestMap.remove(opaque); + } + + @Override + public void clearExpireContext() { + Iterator> iterator = inFlightRequestMap.entrySet().iterator(); + int count = 0; + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (entry.getValue().expired(ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds())) { + iterator.remove(); + count++; + log.debug("An expired request is found, request: {}", entry.getValue()); + } + } + if (count > 0) { + log.warn("[BUG] {} expired in-flight requests is cleaned.", count); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContext.java new file mode 100644 index 0000000000..9fb488eb9b --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContext.java @@ -0,0 +1,43 @@ +/* + * 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.service.channel; + +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public class InvocationContext implements InvocationContextInterface { + private final CompletableFuture response; + private final long timestamp = System.currentTimeMillis(); + + public InvocationContext(CompletableFuture resp) { + this.response = resp; + } + + public boolean expired(long expiredTimeSec) { + return System.currentTimeMillis() - timestamp >= Duration.ofSeconds(expiredTimeSec).toMillis(); + } + + public CompletableFuture getResponse() { + return response; + } + + public void handle(RemotingCommand remotingCommand) { + response.complete(remotingCommand); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContextInterface.java similarity index 76% rename from proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContextInterface.java index a02b08a913..0db9516486 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/Cleaner.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContextInterface.java @@ -15,8 +15,12 @@ * limitations under the License. */ -package org.apache.rocketmq.proxy.common; +package org.apache.rocketmq.proxy.service.channel; -public interface Cleaner { - void clean(); +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public interface InvocationContextInterface { + void handle(RemotingCommand remotingCommand); + + boolean expired(long expiredTimeSec); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java index 3e2ea4562a..9f010526b8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java @@ -22,6 +22,7 @@ import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.DefaultChannelPromise; @@ -45,6 +46,7 @@ public class SimpleChannel extends AbstractChannel { protected final String localAddress; protected long lastAccessTime; + protected ChannelHandlerContext channelHandlerContext; /** * Creates a new instance. @@ -58,6 +60,7 @@ public class SimpleChannel extends AbstractChannel { lastAccessTime = System.currentTimeMillis(); this.remoteAddress = remoteAddress; this.localAddress = localAddress; + this.channelHandlerContext = new SimpleChannelHandlerContext(this); } public SimpleChannel(String remoteAddress, String localAddress) { @@ -165,4 +168,24 @@ public class SimpleChannel extends AbstractChannel { promise.setSuccess(); return promise; } + + public void updateLastAccessTime() { + this.lastAccessTime = System.currentTimeMillis(); + } + + public void registerInvocationContext(int opaque, InvocationContextInterface context) { + + } + + public void eraseInvocationContext(int opaque) { + + } + + public void clearExpireContext() { + + } + + public ChannelHandlerContext getChannelHandlerContext() { + return channelHandlerContext; + } } \ No newline at end of file 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 055f9e85e1..c18e8fe4d1 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 @@ -16,37 +16,121 @@ */ package org.apache.rocketmq.proxy.service.message; +import io.netty.channel.ChannelHandlerContext; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; 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.service.channel.ChannelManager; +import org.apache.rocketmq.proxy.service.channel.InvocationContext; +import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LocalMessageService implements MessageService { + private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + private final BrokerController brokerController; + private final ChannelManager channelManager; - private BrokerController brokerController; - - public LocalMessageService(BrokerController brokerController, RPCHook rpcHook) { + public LocalMessageService(BrokerController brokerController, ChannelManager channelManager, RPCHook rpcHook) { this.brokerController = brokerController; + this.channelManager = channelManager; } @Override public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { - return null; + byte[] body; + String messageId; + if (msgList.size() > 1) { + requestHeader.setBatch(true); + MessageBatch msgBatch = MessageBatch.generateFromList(msgList); + MessageClientIDSetter.setUniqID(msgBatch); + body = msgBatch.encode(); + msgBatch.setBody(body); + messageId = MessageClientIDSetter.getUniqID(msgBatch); + } else { + Message message = msgList.get(0); + body = message.getBody(); + messageId = MessageClientIDSetter.getUniqID(message); + } + RemotingCommand request = LocalRemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); + request.setBody(body); + CompletableFuture future = new CompletableFuture<>(); + SimpleChannel channel = channelManager.createInvocationChannel(ctx); + InvocationContext invocationContext = new InvocationContext(future); + channel.registerInvocationContext(request.getOpaque(), invocationContext); + ChannelHandlerContext simpleChannelHandlerContext = channel.getChannelHandlerContext(); + try { + RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, request); + if (response != null) { + invocationContext.handle(response); + } + } catch (Exception e) { + future.completeExceptionally(e); + log.error("Failed to process send message command", e); + } finally { + channel.eraseInvocationContext(request.getOpaque()); + } + return future.thenApply(r -> { + SendResult sendResult = new SendResult(); + SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) r.readCustomHeader(); + SendStatus sendStatus; + switch (r.getCode()) { + case ResponseCode.FLUSH_DISK_TIMEOUT: { + sendStatus = SendStatus.FLUSH_DISK_TIMEOUT; + break; + } + case ResponseCode.FLUSH_SLAVE_TIMEOUT: { + sendStatus = SendStatus.FLUSH_SLAVE_TIMEOUT; + break; + } + case ResponseCode.SLAVE_NOT_AVAILABLE: { + sendStatus = SendStatus.SLAVE_NOT_AVAILABLE; + break; + } + case ResponseCode.SUCCESS: { + sendStatus = SendStatus.SEND_OK; + break; + } + default: { + throw new ProxyException(ProxyExceptionCode.ILLEGAL_MESSAGE, r.getRemark()); + } + } + sendResult.setSendStatus(sendStatus); + sendResult.setMsgId(messageId); + sendResult.setMessageQueue(new MessageQueue(requestHeader.getTopic(), brokerController.getBrokerConfig().getBrokerName(), requestHeader.getQueueId())); + sendResult.setQueueOffset(responseHeader.getQueueOffset()); + sendResult.setTransactionId(responseHeader.getTransactionId()); + sendResult.setOffsetMsgId(responseHeader.getMsgId()); + return Collections.singletonList(sendResult); + }); } @Override diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java new file mode 100644 index 0000000000..7053e08e26 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.message; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.BrokerConfig; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageBatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.proxy.common.ContextVariable; +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.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.service.channel.ChannelManager; +import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowableOfType; + +@RunWith(MockitoJUnitRunner.class) +public class LocalMessageServiceTest extends InitConfigAndLoggerTest { + private LocalMessageService localMessageService; + @Mock + private SendMessageProcessor sendMessageProcessorMock; + @Mock + private BrokerController brokerControllerMock; + + private ProxyContext proxyContext; + + private ChannelManager channelManager; + + private String topic = "topic"; + + private int queueId = 0; + + private long queueOffset = 0L; + + private String transactionId = "transactionId"; + + private String offsetMessageId = "offsetMessageId"; + + @Before + public void setUp() throws Throwable { + super.before(); + ConfigurationManager.getProxyConfig().setNameSrvAddr("1.1.1.1"); + channelManager = new ChannelManager(); + Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); + localMessageService = new LocalMessageService(brokerControllerMock, channelManager, null); + proxyContext = ProxyContext.create().withVal(ContextVariable.REMOTE_ADDRESS, "0.0.0.1") + .withVal(ContextVariable.LOCAL_ADDRESS, "0.0.0.2"); + } + + @Test + public void testSendMessageWriteAndFlush() throws Exception { + Message message = new Message(topic, "body".getBytes(StandardCharsets.UTF_8)); + MessageClientIDSetter.setUniqID(message); + List messagesList = Collections.singletonList(message); + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.SEND_MESSAGE; + boolean second = Arrays.equals(argument.getBody(), message.getBody()); + return first & second; + }))).thenAnswer(invocation -> { + SimpleChannelHandlerContext simpleChannelHandlerContext = invocation.getArgument(0); + RemotingCommand request = invocation.getArgument(1); + RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class); + response.setOpaque(request.getOpaque()); + response.setCode(ResponseCode.SUCCESS); + response.setBody(message.getBody()); + SendMessageResponseHeader sendMessageResponseHeader = (SendMessageResponseHeader) response.readCustomHeader(); + sendMessageResponseHeader.setQueueId(queueId); + sendMessageResponseHeader.setQueueOffset(queueOffset); + sendMessageResponseHeader.setMsgId(offsetMessageId); + sendMessageResponseHeader.setTransactionId(transactionId); + simpleChannelHandlerContext.writeAndFlush(response); + return null; + }); + + CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); + SendResult sendResult = future.get(); + assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK); + assertThat(sendResult.getMsgId()).isEqualTo(MessageClientIDSetter.getUniqID(message)); + assertThat(sendResult.getMessageQueue()) + .isEqualTo(new MessageQueue(topic, brokerControllerMock.getBrokerConfig().getBrokerName(), queueId)); + assertThat(sendResult.getQueueOffset()).isEqualTo(queueOffset); + assertThat(sendResult.getTransactionId()).isEqualTo(transactionId); + assertThat(sendResult.getOffsetMsgId()).isEqualTo(offsetMessageId); + } + + @Test + public void testSendBatchMessageWriteAndFlush() throws Exception { + Message message1 = new Message(topic, "body1".getBytes(StandardCharsets.UTF_8)); + Message message2 = new Message(topic, "body2".getBytes(StandardCharsets.UTF_8)); + MessageClientIDSetter.setUniqID(message1); + MessageClientIDSetter.setUniqID(message2); + List messagesList = Arrays.asList(message1, message2); + MessageBatch msgBatch = MessageBatch.generateFromList(messagesList); + MessageClientIDSetter.setUniqID(msgBatch); + byte[] body = msgBatch.encode(); + msgBatch.setBody(body); + SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); + requestHeader.setTopic(topic); + requestHeader.setQueueId(queueId); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.SEND_MESSAGE; + boolean second = Arrays.equals(argument.getBody(), body); + return first & second; + }))).thenAnswer(invocation -> { + SimpleChannelHandlerContext simpleChannelHandlerContext = invocation.getArgument(0); + RemotingCommand request = invocation.getArgument(1); + RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class); + response.setOpaque(request.getOpaque()); + response.setCode(ResponseCode.SUCCESS); + response.setBody(body); + SendMessageResponseHeader sendMessageResponseHeader = (SendMessageResponseHeader) response.readCustomHeader(); + sendMessageResponseHeader.setQueueId(queueId); + sendMessageResponseHeader.setQueueOffset(queueOffset); + sendMessageResponseHeader.setMsgId(offsetMessageId); + sendMessageResponseHeader.setTransactionId(transactionId); + simpleChannelHandlerContext.writeAndFlush(response); + return null; + }); + + CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); + SendResult sendResult = future.get(); + assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK); + assertThat(sendResult.getMessageQueue()) + .isEqualTo(new MessageQueue(topic, brokerControllerMock.getBrokerConfig().getBrokerName(), queueId)); + assertThat(sendResult.getQueueOffset()).isEqualTo(queueOffset); + assertThat(sendResult.getTransactionId()).isEqualTo(transactionId); + assertThat(sendResult.getOffsetMsgId()).isEqualTo(offsetMessageId); + } + + @Test + public void testSendMessageError() throws Exception { + RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class); + response.setCode(ResponseCode.SYSTEM_ERROR); + Message message = new Message("topic", "body".getBytes(StandardCharsets.UTF_8)); + MessageClientIDSetter.setUniqID(message); + List messagesList = Collections.singletonList(message); + SendMessageRequestHeader sendMessageRequestHeader = new SendMessageRequestHeader(); + sendMessageRequestHeader.setTopic(topic); + sendMessageRequestHeader.setQueueId(queueId); + + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenReturn(response); + + CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); + ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); + assertThat(exception.getCause()).isInstanceOf(ProxyException.class); + assertThat(((ProxyException) exception.getCause()).getCode()).isEqualTo(ProxyExceptionCode.ILLEGAL_MESSAGE); + } + + @Test + public void testSendMessageWithException() throws Exception { + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) + .thenThrow(new RemotingCommandException("test")); + Message message = new Message("topic", "body".getBytes(StandardCharsets.UTF_8)); + MessageClientIDSetter.setUniqID(message); + List messagesList = Collections.singletonList(message); + SendMessageRequestHeader sendMessageRequestHeader = new SendMessageRequestHeader(); + CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); + ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); + assertThat(exception.getCause()).isInstanceOf(RemotingCommandException.class); + } +} \ No newline at end of file From f87cc20d36e612414405a2faf4c7b40f8d629342 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 23 May 2022 19:02:02 +0800 Subject: [PATCH 196/338] [ISSUE #3949] Remove nextVisibleTime in ReceiptHandle --- .../common/consumer/ReceiptHandle.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java index 5b02418f44..8d5d62c1a9 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -66,7 +66,7 @@ public class ReceiptHandle { long retrieveTime = Long.parseLong(dataList.get(1)); long invisibleTime = Long.parseLong(dataList.get(2)); int reviveQueueId = Integer.parseInt(dataList.get(3)); - String topic = dataList.get(4); + String topicType = dataList.get(4); String brokerName = dataList.get(5); int queueId = Integer.parseInt(dataList.get(6)); long offset = Long.parseLong(dataList.get(7)); @@ -80,11 +80,10 @@ public class ReceiptHandle { .retrieveTime(retrieveTime) .invisibleTime(invisibleTime) .reviveQueueId(reviveQueueId) - .topicType(topic) + .topicType(topicType) .brokerName(brokerName) .queueId(queueId) .offset(offset) - .nextVisibleTime(retrieveTime + invisibleTime) .commitLogOffset(commitLogOffset) .receiptHandle(receiptHandle).build(); } @@ -109,7 +108,6 @@ public class ReceiptHandle { private long startOffset; private long retrieveTime; private long invisibleTime; - private long nextVisibleTime; private int reviveQueueId; private String topicType; private String brokerName; @@ -136,18 +134,13 @@ public class ReceiptHandle { return this; } - public ReceiptHandle.ReceiptHandleBuilder nextVisibleTime(final long nextVisibleTime) { - this.nextVisibleTime = nextVisibleTime; - return this; - } - public ReceiptHandle.ReceiptHandleBuilder reviveQueueId(final int reviveQueueId) { this.reviveQueueId = reviveQueueId; return this; } - public ReceiptHandle.ReceiptHandleBuilder topicType(final String topic) { - this.topicType = topic; + public ReceiptHandle.ReceiptHandleBuilder topicType(final String topicType) { + this.topicType = topicType; return this; } @@ -177,13 +170,13 @@ public class ReceiptHandle { } public ReceiptHandle build() { - return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.nextVisibleTime, + return new ReceiptHandle(this.startOffset, this.retrieveTime, this.invisibleTime, this.retrieveTime + this.invisibleTime, this.reviveQueueId, this.topicType, this.brokerName, this.queueId, this.offset, this.commitLogOffset, this.receiptHandle); } @Override public String toString() { - return "ReceiptHandle.ReceiptHandleBuilder(startOffset=" + this.startOffset + ", retrieveTime=" + this.retrieveTime + ", invisibleTime=" + this.invisibleTime + ", nextVisibleTime=" + this.nextVisibleTime + ", reviveQueueId=" + this.reviveQueueId + ", topic=" + this.topicType + ", brokerName=" + this.brokerName + ", queueId=" + this.queueId + ", offset=" + this.offset + ", commitLogOffset=" + this.commitLogOffset + ", receiptHandle=" + this.receiptHandle + ")"; + return "ReceiptHandle.ReceiptHandleBuilder(startOffset=" + this.startOffset + ", retrieveTime=" + this.retrieveTime + ", invisibleTime=" + this.invisibleTime + ", reviveQueueId=" + this.reviveQueueId + ", topic=" + this.topicType + ", brokerName=" + this.brokerName + ", queueId=" + this.queueId + ", offset=" + this.offset + ", commitLogOffset=" + this.commitLogOffset + ", receiptHandle=" + this.receiptHandle + ")"; } } From 41e5cdafe862e94429f39984b37cf92f407d2b3e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 23 May 2022 19:02:54 +0800 Subject: [PATCH 197/338] [ISSUE #3949] Complete LocalMessageService --- .../proxy/common/ProxyExceptionCode.java | 1 + .../grpc/v2/common/GrpcProxyException.java | 1 + .../service/message/LocalMessageService.java | 194 +++++++++++++- .../processor/ProducerProcessorTest.java | 6 +- .../message/LocalMessageServiceTest.java | 243 ++++++++++++++++++ 5 files changed, 434 insertions(+), 11 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index a297e50aed..2fbe49ef43 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -22,4 +22,5 @@ public enum ProxyExceptionCode { INVALID_BROKER_NAME, INVALID_RECEIPT_HANDLE, ILLEGAL_MESSAGE, + INTERNAL_SERVER_ERROR, } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index 7cd5f5a43d..ed1eaf1197 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -35,6 +35,7 @@ public class GrpcProxyException extends RuntimeException { CODE_MAPPING.put(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, Code.RECEIPT_HANDLE_EXPIRED); CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); CODE_MAPPING.put(ProxyExceptionCode.ILLEGAL_MESSAGE, Code.ILLEGAL_MESSAGE); + CODE_MAPPING.put(ProxyExceptionCode.INTERNAL_SERVER_ERROR, Code.INTERNAL_SERVER_ERROR); } public GrpcProxyException(Code code, String message) { 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 c18e8fe4d1..4e893c384f 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 @@ -17,13 +17,18 @@ package org.apache.rocketmq.proxy.service.message; import io.netty.channel.ChannelHandlerContext; -import java.util.Arrays; +import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.constant.LoggerName; @@ -31,14 +36,20 @@ import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -94,7 +105,7 @@ public class LocalMessageService implements MessageService { } } catch (Exception e) { future.completeExceptionally(e); - log.error("Failed to process send message command", e); + log.error("Failed to process sendMessage command", e); } finally { channel.eraseInvocationContext(request.getOpaque()); } @@ -136,27 +147,196 @@ public class LocalMessageService implements MessageService { @Override public CompletableFuture sendMessageBack(ProxyContext ctx, ReceiptHandle handle, String messageId, ConsumerSendMsgBackRequestHeader requestHeader, long timeoutMillis) { - return null; + SimpleChannel channel = channelManager.createChannel(ctx); + ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); + RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.CONSUMER_SEND_MSG_BACK, requestHeader); + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand response = brokerController.getSendMessageProcessor() + .processRequest(channelHandlerContext, command); + future.complete(response); + } catch (Exception e) { + log.error("Fail to process sendMessageBack command", e); + future.completeExceptionally(e); + } + return future; } @Override public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, EndTransactionRequestHeader requestHeader, long timeoutMillis) { - + SimpleChannel channel = channelManager.createChannel(ctx); + ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); + RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); + try { + brokerController.getEndTransactionProcessor() + .processRequest(channelHandlerContext, command); + } catch (Exception e) { + log.error("Fail to process endTransaction command", e); + } } @Override public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis) { - return null; + RemotingCommand request = LocalRemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); + CompletableFuture future = new CompletableFuture<>(); + SimpleChannel channel = channelManager.createInvocationChannel(ctx); + InvocationContext invocationContext = new InvocationContext(future); + channel.registerInvocationContext(request.getOpaque(), invocationContext); + ChannelHandlerContext simpleChannelHandlerContext = channel.getChannelHandlerContext(); + try { + RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(simpleChannelHandlerContext, request); + if (response != null) { + invocationContext.handle(response); + } + } catch (Exception e) { + future.completeExceptionally(e); + log.error("Failed to process popMessage command", e); + } finally { + channel.eraseInvocationContext(request.getOpaque()); + } + return future.thenApply(r -> { + PopStatus popStatus; + List messageExtList = new ArrayList<>(); + switch (r.getCode()) { + case ResponseCode.SUCCESS: + popStatus = PopStatus.FOUND; + ByteBuffer byteBuffer = ByteBuffer.wrap(r.getBody()); + messageExtList = MessageDecoder.decodes(byteBuffer); + break; + case ResponseCode.POLLING_FULL: + popStatus = PopStatus.POLLING_FULL; + break; + case ResponseCode.POLLING_TIMEOUT: + case ResponseCode.PULL_NOT_FOUND: + popStatus = PopStatus.POLLING_NOT_FOUND; + break; + default: + throw new ProxyException(ProxyExceptionCode.INTERNAL_SERVER_ERROR, r.getRemark()); + } + PopResult popResult = new PopResult(popStatus, messageExtList); + PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) r.readCustomHeader(); + + if (popStatus == PopStatus.FOUND) { + Map startOffsetInfo = null; + Map> msgOffsetInfo = null; + Map orderCountInfo = null; + if (requestHeader != null) { + popResult.setInvisibleTime(responseHeader.getInvisibleTime()); + popResult.setPopTime(responseHeader.getPopTime()); + startOffsetInfo = ExtraInfoUtil.parseStartOffsetInfo(responseHeader.getStartOffsetInfo()); + msgOffsetInfo = ExtraInfoUtil.parseMsgOffsetInfo(responseHeader.getMsgOffsetInfo()); + orderCountInfo = ExtraInfoUtil.parseOrderCountInfo(responseHeader.getOrderCountInfo()); + } + // + Map> sortMap = new HashMap<>(16); + for (MessageExt messageExt : messageExtList) { + String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); + if (!sortMap.containsKey(key)) { + sortMap.put(key, new ArrayList<>(4)); + } + sortMap.get(key).add(messageExt.getQueueOffset()); + } + Map map = new HashMap<>(5); + for (MessageExt messageExt : messageExtList) { + if (requestHeader != null) { + if (startOffsetInfo == null) { + // we should set the check point info to extraInfo field , if the command is popMsg + // find pop ck offset + String key = messageExt.getTopic() + messageExt.getQueueId(); + if (!map.containsKey(messageExt.getTopic() + messageExt.getQueueId())) { + map.put(key, ExtraInfoUtil.buildExtraInfo(messageExt.getQueueOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), responseHeader.getReviveQid(), + messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId())); + } + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, map.get(key) + MessageConst.KEY_SEPARATOR + messageExt.getQueueOffset()); + } else { + String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); + int index = sortMap.get(key).indexOf(messageExt.getQueueOffset()); + Long msgQueueOffset = msgOffsetInfo.get(key).get(index); + if (msgQueueOffset != messageExt.getQueueOffset()) { + log.warn("Queue offset [{}] of msg is strange, not equal to the stored in msg, {}", msgQueueOffset, messageExt); + } + + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, + ExtraInfoUtil.buildExtraInfo(startOffsetInfo.get(key), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), + responseHeader.getReviveQid(), messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId(), msgQueueOffset) + ); + if (requestHeader.isOrder() && orderCountInfo != null) { + Integer count = orderCountInfo.get(key); + if (count != null && count > 0) { + messageExt.setReconsumeTimes(count); + } + } + } + messageExt.getProperties().computeIfAbsent(MessageConst.PROPERTY_FIRST_POP_TIME, k -> String.valueOf(responseHeader.getPopTime())); + } + messageExt.setBrokerName(messageExt.getBrokerName()); + } + } + return popResult; + }); } @Override public CompletableFuture changeInvisibleTime(ProxyContext ctx, ReceiptHandle handle, String messageId, ChangeInvisibleTimeRequestHeader requestHeader, long timeoutMillis) { - return null; + SimpleChannel channel = channelManager.createChannel(ctx); + ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); + RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.CHANGE_MESSAGE_INVISIBLETIME, requestHeader); + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand response = brokerController.getChangeInvisibleTimeProcessor() + .processRequest(channelHandlerContext, command); + future.complete(response); + } catch (Exception e) { + log.error("Fail to process changeInvisibleTime command", e); + future.completeExceptionally(e); + } + return future.thenApply(r -> { + ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) r.readCustomHeader(); + AckResult ackResult = new AckResult(); + if (ResponseCode.SUCCESS == r.getCode()) { + ackResult.setStatus(AckStatus.OK); + } else { + ackResult.setStatus(AckStatus.NO_EXIST); + } + ackResult.setPopTime(responseHeader.getPopTime()); + ackResult.setExtraInfo(ReceiptHandle.builder() + .startOffset(handle.getStartOffset()) + .retrieveTime(responseHeader.getPopTime()) + .invisibleTime(responseHeader.getInvisibleTime()) + .reviveQueueId(responseHeader.getReviveQid()) + .topicType(handle.getTopicType()) + .brokerName(handle.getBrokerName()) + .queueId(handle.getQueueId()) + .offset(handle.getOffset()) + .build() + .encode()); + return ackResult; + }); } @Override public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, AckMessageRequestHeader requestHeader, long timeoutMillis) { - return null; + SimpleChannel channel = channelManager.createChannel(ctx); + ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); + RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.ACK_MESSAGE, requestHeader); + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand response = brokerController.getAckMessageProcessor() + .processRequest(channelHandlerContext, command); + future.complete(response); + } catch (Exception e) { + log.error("Fail to process ackMessage 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; + }); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 4bac51a5d8..eac0abe553 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -26,7 +26,6 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; @@ -34,8 +33,6 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -44,7 +41,8 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java index 7053e08e26..64ba5cba71 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java @@ -17,23 +17,45 @@ package org.apache.rocketmq.proxy.service.message; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.processor.AckMessageProcessor; +import org.apache.rocketmq.broker.processor.ChangeInvisibleTimeProcessor; +import org.apache.rocketmq.broker.processor.EndTransactionProcessor; +import org.apache.rocketmq.broker.processor.PopMessageProcessor; import org.apache.rocketmq.broker.processor.SendMessageProcessor; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.BrokerConfig; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.proxy.common.ContextVariable; @@ -44,6 +66,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.service.channel.ChannelManager; import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; @@ -62,6 +85,14 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { @Mock private SendMessageProcessor sendMessageProcessorMock; @Mock + private EndTransactionProcessor endTransactionProcessorMock; + @Mock + private PopMessageProcessor popMessageProcessorMock; + @Mock + private ChangeInvisibleTimeProcessor changeInvisibleTimeProcessorMock; + @Mock + private AckMessageProcessor ackMessageProcessorMock; + @Mock private BrokerController brokerControllerMock; private ProxyContext proxyContext; @@ -70,6 +101,8 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { private String topic = "topic"; + private String brokerName = "brokerName"; + private int queueId = 0; private long queueOffset = 0L; @@ -84,6 +117,10 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { ConfigurationManager.getProxyConfig().setNameSrvAddr("1.1.1.1"); channelManager = new ChannelManager(); Mockito.when(brokerControllerMock.getSendMessageProcessor()).thenReturn(sendMessageProcessorMock); + Mockito.when(brokerControllerMock.getPopMessageProcessor()).thenReturn(popMessageProcessorMock); + Mockito.when(brokerControllerMock.getChangeInvisibleTimeProcessor()).thenReturn(changeInvisibleTimeProcessorMock); + Mockito.when(brokerControllerMock.getAckMessageProcessor()).thenReturn(ackMessageProcessorMock); + Mockito.when(brokerControllerMock.getEndTransactionProcessor()).thenReturn(endTransactionProcessorMock); Mockito.when(brokerControllerMock.getBrokerConfig()).thenReturn(new BrokerConfig()); localMessageService = new LocalMessageService(brokerControllerMock, channelManager, null); proxyContext = ProxyContext.create().withVal(ContextVariable.REMOTE_ADDRESS, "0.0.0.1") @@ -205,4 +242,210 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); assertThat(exception.getCause()).isInstanceOf(RemotingCommandException.class); } + + @Test + public void testSendMessageBack() throws Exception { + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""); + Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.CONSUMER_SEND_MSG_BACK; + boolean second = argument.readCustomHeader() instanceof ConsumerSendMsgBackRequestHeader; + return first && second; + }))).thenReturn(remotingCommand); + ConsumerSendMsgBackRequestHeader requestHeader = new ConsumerSendMsgBackRequestHeader(); + CompletableFuture future = localMessageService.sendMessageBack(proxyContext, null, null, requestHeader, 1000L); + RemotingCommand response = future.get(); + assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS); + } + + @Test + public void testEndTransaction() throws Exception { + EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); + localMessageService.endTransactionOneway(proxyContext, null, requestHeader, 1000L); + Mockito.verify(endTransactionProcessorMock, Mockito.times(1)).processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.END_TRANSACTION; + boolean second = argument.readCustomHeader() instanceof EndTransactionRequestHeader; + return first && second; + })); + } + + @Test + public void testPopMessageWriteAndFlush() throws Exception { + int reviveQueueId = 1; + long popTime = System.currentTimeMillis(); + long invisibleTime = 3000L; + long startOffset = 100L; + long restNum = 0L; + StringBuilder startOffsetStringBuilder = new StringBuilder(); + StringBuilder messageOffsetStringBuilder = new StringBuilder(); + List messageExtList = new ArrayList<>(); + List messageOffsetList = new ArrayList<>(); + MessageExt message1 = buildMessageExt(topic, 0, startOffset); + messageExtList.add(message1); + messageOffsetList.add(startOffset); + byte[] body1 = MessageDecoder.encode(message1, false); + MessageExt message2 = buildMessageExt(topic, 0, startOffset + 1); + messageExtList.add(message2); + messageOffsetList.add(startOffset + 1); + ExtraInfoUtil.buildStartOffsetInfo(startOffsetStringBuilder, false, queueId, startOffset); + ExtraInfoUtil.buildMsgOffsetInfo(messageOffsetStringBuilder, false, queueId, messageOffsetList); + byte[] body2 = MessageDecoder.encode(message2, false); + ByteBuffer byteBuffer1 = ByteBuffer.wrap(body1); + ByteBuffer byteBuffer2 = ByteBuffer.wrap(body2); + ByteBuffer b3 = ByteBuffer.allocate(byteBuffer1.limit() + byteBuffer2.limit()); + b3.put(byteBuffer1); + b3.put(byteBuffer2); + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + requestHeader.setInvisibleTime(invisibleTime); + Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.POP_MESSAGE; + boolean second = argument.readCustomHeader() instanceof PopMessageRequestHeader; + return first && second; + }))).thenAnswer(invocation -> { + SimpleChannelHandlerContext simpleChannelHandlerContext = invocation.getArgument(0); + RemotingCommand request = invocation.getArgument(1); + RemotingCommand response = RemotingCommand.createResponseCommand(PopMessageResponseHeader.class); + response.setOpaque(request.getOpaque()); + response.setCode(ResponseCode.SUCCESS); + response.setBody(b3.array()); + PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) response.readCustomHeader(); + responseHeader.setStartOffsetInfo(startOffsetStringBuilder.toString()); + responseHeader.setMsgOffsetInfo(messageOffsetStringBuilder.toString()); + responseHeader.setInvisibleTime(requestHeader.getInvisibleTime()); + responseHeader.setPopTime(popTime); + responseHeader.setRestNum(restNum); + responseHeader.setReviveQid(reviveQueueId); + simpleChannelHandlerContext.writeAndFlush(response); + return null; + }); + MessageQueue messageQueue = new MessageQueue(topic, brokerName, queueId); + CompletableFuture future = localMessageService.popMessage(proxyContext, new SelectableMessageQueue(messageQueue, ""), requestHeader, 1000L); + PopResult popResult = future.get(); + assertThat(popResult.getPopTime()).isEqualTo(popTime); + assertThat(popResult.getInvisibleTime()).isEqualTo(invisibleTime); + assertThat(popResult.getPopStatus()).isEqualTo(PopStatus.FOUND); + assertThat(popResult.getRestNum()).isEqualTo(restNum); + assertThat(popResult.getMsgFoundList().size()).isEqualTo(messageExtList.size()); + for (int i = 0; i < popResult.getMsgFoundList().size(); i++) { + assertMessageExt(popResult.getMsgFoundList().get(i), messageExtList.get(i)); + } + } + + @Test + public void testPopMessagePollingTimeout() throws Exception { + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.POLLING_TIMEOUT, ""); + Mockito.when(popMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.POP_MESSAGE; + boolean second = argument.readCustomHeader() instanceof PopMessageRequestHeader; + return first && second; + }))).thenReturn(remotingCommand); + PopMessageRequestHeader requestHeader = new PopMessageRequestHeader(); + CompletableFuture future = localMessageService.popMessage(proxyContext, null, requestHeader, 1000L); + PopResult popResult = future.get(); + assertThat(popResult.getPopStatus()).isEqualTo(PopStatus.POLLING_NOT_FOUND); + } + + @Test + public void testChangeInvisibleTime() throws Exception { + String messageId = "messageId"; + long popTime = System.currentTimeMillis(); + long invisibleTime = 3000L; + int reviveQueueId = 1; + ReceiptHandle handle = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(popTime) + .invisibleTime(invisibleTime) + .reviveQueueId(reviveQueueId) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(brokerName) + .queueId(queueId) + .offset(queueOffset) + .build(); + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ChangeInvisibleTimeResponseHeader.class); + remotingCommand.setCode(ResponseCode.SUCCESS); + remotingCommand.setRemark(""); + long newPopTime = System.currentTimeMillis(); + long newInvisibleTime = 5000L; + int newReviveQueueId = 2; + ChangeInvisibleTimeResponseHeader responseHeader = (ChangeInvisibleTimeResponseHeader) remotingCommand.readCustomHeader(); + responseHeader.setReviveQid(newReviveQueueId); + responseHeader.setInvisibleTime(newInvisibleTime); + responseHeader.setPopTime(newPopTime); + Mockito.when(changeInvisibleTimeProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.CHANGE_MESSAGE_INVISIBLETIME; + boolean second = argument.readCustomHeader() instanceof ChangeInvisibleTimeRequestHeader; + return first && second; + }))).thenReturn(remotingCommand); + ChangeInvisibleTimeRequestHeader requestHeader = new ChangeInvisibleTimeRequestHeader(); + CompletableFuture future = localMessageService.changeInvisibleTime(proxyContext, handle, messageId, + requestHeader, 1000L); + AckResult ackResult = future.get(); + assertThat(ackResult.getStatus()).isEqualTo(AckStatus.OK); + assertThat(ackResult.getPopTime()).isEqualTo(newPopTime); + assertThat(ackResult.getExtraInfo()).isEqualTo(ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(newPopTime) + .invisibleTime(newInvisibleTime) + .reviveQueueId(newReviveQueueId) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(brokerName) + .queueId(queueId) + .offset(queueOffset) + .build() + .encode()); + } + + @Test + public void testAckMessage() throws Exception { + String messageId = "messageId"; + long popTime = System.currentTimeMillis(); + long invisibleTime = 3000L; + int reviveQueueId = 1; + ReceiptHandle handle = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(popTime) + .invisibleTime(invisibleTime) + .reviveQueueId(reviveQueueId) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(brokerName) + .queueId(queueId) + .offset(queueOffset) + .build(); + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, null); + Mockito.when(ackMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.argThat(argument -> { + boolean first = argument.getCode() == RequestCode.ACK_MESSAGE; + boolean second = argument.readCustomHeader() instanceof AckMessageRequestHeader; + return first && second; + }))).thenReturn(remotingCommand); + AckMessageRequestHeader requestHeader = new AckMessageRequestHeader(); + CompletableFuture future = localMessageService.ackMessage(proxyContext, handle, messageId, + requestHeader, 1000L); + AckResult ackResult = future.get(); + assertThat(ackResult.getStatus()).isEqualTo(AckStatus.OK); + } + + private MessageExt buildMessageExt(String topic, int queueId, long queueOffset) { + MessageExt message1 = new MessageExt(); + message1.setTopic(topic); + message1.setBody("body".getBytes(StandardCharsets.UTF_8)); + message1.setFlag(0); + message1.setQueueId(queueId); + message1.setQueueOffset(queueOffset); + message1.setCommitLogOffset(1000L); + message1.setSysFlag(0); + message1.setBornTimestamp(0L); + InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 80); + message1.setBornHost(inetSocketAddress); + message1.setStoreHost(inetSocketAddress); + message1.setReconsumeTimes(0); + message1.setPreparedTransactionOffset(0L); + message1.putUserProperty("K", "V"); + return message1; + } + + private void assertMessageExt(MessageExt messageExt1, MessageExt messageExt2) { + assertThat(messageExt1.getBody()).isEqualTo(messageExt2.getBody()); + assertThat(messageExt1.getTopic()).isEqualTo(messageExt2.getTopic()); + assertThat(messageExt1.getQueueId()).isEqualTo(messageExt2.getQueueId()); + assertThat(messageExt1.getQueueOffset()).isEqualTo(messageExt2.getQueueOffset()); + } } \ No newline at end of file From dfacfe607fc8d073eadda4a7ed7ff045a599ebf4 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 23 May 2022 19:15:26 +0800 Subject: [PATCH 198/338] [ISSUE #3949] Update LocalMessageService unit test --- .../service/message/LocalMessageServiceTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java index 64ba5cba71..3058951a2c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java @@ -155,8 +155,8 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { return null; }); - CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); - SendResult sendResult = future.get(); + CompletableFuture> future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); + SendResult sendResult = future.get().get(0); assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK); assertThat(sendResult.getMsgId()).isEqualTo(MessageClientIDSetter.getUniqID(message)); assertThat(sendResult.getMessageQueue()) @@ -200,8 +200,8 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { return null; }); - CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); - SendResult sendResult = future.get(); + CompletableFuture> future = localMessageService.sendMessage(proxyContext, null, messagesList, requestHeader, 1000L); + SendResult sendResult = future.get().get(0); assertThat(sendResult.getSendStatus()).isEqualTo(SendStatus.SEND_OK); assertThat(sendResult.getMessageQueue()) .isEqualTo(new MessageQueue(topic, brokerControllerMock.getBrokerConfig().getBrokerName(), queueId)); @@ -224,7 +224,7 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { Mockito.when(sendMessageProcessorMock.processRequest(Mockito.any(SimpleChannelHandlerContext.class), Mockito.any(RemotingCommand.class))) .thenReturn(response); - CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); + CompletableFuture> future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); assertThat(exception.getCause()).isInstanceOf(ProxyException.class); assertThat(((ProxyException) exception.getCause()).getCode()).isEqualTo(ProxyExceptionCode.ILLEGAL_MESSAGE); @@ -238,7 +238,7 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { MessageClientIDSetter.setUniqID(message); List messagesList = Collections.singletonList(message); SendMessageRequestHeader sendMessageRequestHeader = new SendMessageRequestHeader(); - CompletableFuture future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); + CompletableFuture> future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); assertThat(exception.getCause()).isInstanceOf(RemotingCommandException.class); } From a45b040fba5f051a81ae2ddb0b9d0e2fde86cb17 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 23 May 2022 19:12:58 +0800 Subject: [PATCH 199/338] [ISSUE #3949] add test cases --- .../proxy/grpc/v2/client/ClientActivity.java | 16 +- .../proxy/service/ClusterServiceManager.java | 14 +- .../metadata/ClusterMetadataService.java | 18 +- .../service/route/MessageQueueSelector.java | 26 -- .../service/route/TopicRouteService.java | 8 +- .../ClusterTransactionService.java | 27 +- .../proxy/grpc/v2/BaseActivityTest.java | 8 +- .../grpc/v2/client/ClientActivityTest.java | 259 ++++++++++++++++++ .../ForwardMessageToDLQActivityTest.java | 64 +++++ .../EndTransactionActivityTest.java | 101 +++++++ .../proxy/service/BaseServiceTest.java | 83 ++++++ .../metadata/ClusterMetadataServiceTest.java | 73 +++++ .../route/ClusterTopicRouteServiceTest.java | 69 +++++ .../route/LocalTopicRouteServiceTest.java | 102 +++++++ .../route/MessageQueueSelectorTest.java | 84 ++++++ .../ClusterTransactionServiceTest.java | 141 ++++++++++ 16 files changed, 1028 insertions(+), 65 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/BaseServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 5cbcc94244..e4a4e60918 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -129,7 +129,10 @@ public class ClientActivity extends AbstractMessingActivity { break; } default: { - throw new IllegalArgumentException("ClientType not exist " + clientSettings.getClientType()); + future.complete(HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) + .build()); + return future; } } future.complete(HeartbeatResponse.newBuilder() @@ -150,7 +153,7 @@ public class ClientActivity extends AbstractMessingActivity { ProxyContext context = createContext(ctx); String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); - Settings clientSettings = grpcClientSettingsManager.getClientSettings(context); + Settings clientSettings = grpcClientSettingsManager.removeClientSettings(clientId); switch (clientSettings.getClientType()) { case PRODUCER: @@ -158,8 +161,8 @@ public class ClientActivity extends AbstractMessingActivity { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); // user topic name as producer group GrpcClientChannel channel = this.grpcChannelManager.removeChannel(topicName, clientId); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); if (channel != null) { + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); this.messagingProcessor.unRegisterProducer(context, topicName, clientChannelInfo); } } @@ -171,13 +174,16 @@ public class ClientActivity extends AbstractMessingActivity { } String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); GrpcClientChannel channel = this.grpcChannelManager.removeChannel(consumerGroup, clientId); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); if (channel != null) { + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); this.messagingProcessor.unRegisterConsumer(context, consumerGroup, clientChannelInfo); } break; default: - break; + future.complete(NotifyClientTerminationResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) + .build()); + return future; } future.complete(NotifyClientTerminationResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) 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 91604cb13b..ce529b16e1 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 @@ -37,6 +37,7 @@ 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.proxy.service.mqclient.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.mqclient.ProxyClientRemotingProcessor; import org.apache.rocketmq.proxy.service.relay.ClusterProxyRelayService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; @@ -60,6 +61,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S private final ScheduledExecutorService scheduledExecutorService; private final MQClientAPIFactory messagingClientAPIFactory; private final MQClientAPIFactory operationClientAPIFactory; + private final MQClientAPIFactory transactionClientAPIFactory; public ClusterServiceManager(RPCHook rpcHook) { this.scheduledExecutorService = Executors.newScheduledThreadPool(3); @@ -68,7 +70,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); this.messagingClientAPIFactory = new MQClientAPIFactory( - "CLUSTER_MQ_CLIENT_", + "ClusterMQClient_", proxyConfig.getRocketmqMQClientNum(), new DoNothingClientRemotingProcessor(null), rpcHook, @@ -80,10 +82,17 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S rpcHook, this.scheduledExecutorService ); + this.transactionClientAPIFactory = new MQClientAPIFactory( + "ClusterTransaction_", + 1, + new ProxyClientRemotingProcessor(producerManager), + rpcHook, + scheduledExecutorService); this.topicRouteService = new ClusterTopicRouteService(operationClientAPIFactory); this.messageService = new ClusterMessageService(this.topicRouteService, this.messagingClientAPIFactory); - this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook); + this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook, + this.transactionClientAPIFactory); this.proxyRelayService = new ClusterProxyRelayService(); this.metadataService = new ClusterMetadataService(topicRouteService, operationClientAPIFactory); @@ -105,6 +114,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S this.appendShutdown(scheduledExecutorService::shutdown); this.appendStartAndShutdown(this.messagingClientAPIFactory); this.appendStartAndShutdown(this.operationClientAPIFactory); + this.appendStartAndShutdown(this.transactionClientAPIFactory); this.appendStartAndShutdown(this.topicRouteService); this.appendStartAndShutdown(this.clusterTransactionService); this.appendStartAndShutdown(this.metadataService); 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 a5b18636d6..0291289340 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 @@ -22,7 +22,6 @@ import com.google.common.cache.LoadingCache; import java.util.Optional; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.route.BrokerData; @@ -43,15 +42,16 @@ public class ClusterMetadataService extends AbstractStartAndShutdown implements protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private static final long DEFAULT_TIMEOUT = 3000; - private final ThreadPoolExecutor cacheRefreshExecutor; private final TopicRouteService topicRouteService; private final MQClientAPIFactory mqClientAPIFactory; - private final LoadingCache topicCache; - private final static TopicConfigAndQueueMapping EMPTY_TOPIC_CONFIG = new TopicConfigAndQueueMapping(); + protected final ThreadPoolExecutor cacheRefreshExecutor; - private final LoadingCache subscriptionGroupConfigCache; - private final static SubscriptionGroupConfig EMPTY_SUBSCRIPTION_GROUP_CONFIG = new SubscriptionGroupConfig(); + protected final LoadingCache topicConfigCache; + protected final static TopicConfigAndQueueMapping EMPTY_TOPIC_CONFIG = new TopicConfigAndQueueMapping(); + + protected final LoadingCache subscriptionGroupConfigCache; + protected final static SubscriptionGroupConfig EMPTY_SUBSCRIPTION_GROUP_CONFIG = new SubscriptionGroupConfig(); public ClusterMetadataService(TopicRouteService topicRouteService, MQClientAPIFactory mqClientAPIFactory) { this.topicRouteService = topicRouteService; @@ -66,7 +66,7 @@ public class ClusterMetadataService extends AbstractStartAndShutdown implements "MetadataCacheRefresh", config.getMetadataThreadPoolQueueCapacity() ); - this.topicCache = CacheBuilder.newBuilder() + this.topicConfigCache = CacheBuilder.newBuilder() .maximumSize(config.getTopicConfigCacheMaxNum()) .refreshAfterWrite(config.getTopicConfigCacheExpiredInSeconds(), TimeUnit.SECONDS) .build(new ClusterTopicConfigCacheLoader()); @@ -86,7 +86,7 @@ public class ClusterMetadataService extends AbstractStartAndShutdown implements public TopicMessageType getTopicMessageType(String topic) { TopicConfigAndQueueMapping topicConfigAndQueueMapping; try { - topicConfigAndQueueMapping = topicCache.get(topic); + topicConfigAndQueueMapping = topicConfigCache.get(topic); } catch (Exception e) { return TopicMessageType.UNSPECIFIED; } @@ -159,7 +159,7 @@ public class ClusterMetadataService extends AbstractStartAndShutdown implements protected Optional findOneBroker(String topic) throws Exception { try { return topicRouteService.getAllMessageQueueView(topic).getTopicRouteData().getBrokerDatas().stream().findAny(); - } catch (MQClientException e) { + } catch (Exception e) { if (TopicRouteHelper.isTopicNotExistError(e)) { return Optional.empty(); } 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 f37155e319..4c4ccdc49a 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 @@ -152,16 +152,6 @@ public class MessageQueueSelector { return selectOneByIndex(nextIndex, onlyBroker); } - public final SelectableMessageQueue selectOne(String brokerName, int queueId) { - for (SelectableMessageQueue targetMessageQueue : queues) { - String queueBrokerName = targetMessageQueue.getBrokerName(); - if (queueBrokerName.equals(brokerName) && targetMessageQueue.getQueueId() == queueId) { - return targetMessageQueue; - } - } - return null; - } - public final SelectableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { if (onlyBroker) { if (brokerActingQueues.isEmpty()) { @@ -176,22 +166,6 @@ public class MessageQueueSelector { return queues.get(Math.abs(index) % queues.size()); } - // find next same type(but different) queue with last(normal queue or broker acting queue). - public final SelectableMessageQueue selectNextQueue(SelectableMessageQueue last) { - boolean onlyBroker = last.getQueueId() < 0; - SelectableMessageQueue newOne = last; - int count = onlyBroker ? brokerActingQueues.size() : queues.size(); - - for (int i = 0; i < count; i++) { - newOne = selectOne(onlyBroker); - if (!newOne.getBrokerName().equals(last.getBrokerName()) || newOne.getQueueId() != last.getQueueId()) { - break; - } - } - - return newOne; - } - public List getQueues() { return queues; } 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 c800abfa1a..fc9edad5c8 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 @@ -42,11 +42,11 @@ import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; public abstract class TopicRouteService extends AbstractStartAndShutdown { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final LoadingCache topicCache; - private final MQClientAPIFactory mqClientAPIFactory; - private final ScheduledExecutorService scheduledExecutorService; - private final ThreadPoolExecutor cacheRefreshExecutor; + + protected final LoadingCache topicCache; + protected final ScheduledExecutorService scheduledExecutorService; + protected final ThreadPoolExecutor cacheRefreshExecutor; public TopicRouteService(MQClientAPIFactory mqClientAPIFactory) { ProxyConfig config = ConfigurationManager.getProxyConfig(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index c892d3ef74..210f092203 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -26,13 +26,10 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.ServiceThread; -import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; @@ -44,7 +41,6 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; -import org.apache.rocketmq.proxy.service.mqclient.ProxyClientRemotingProcessor; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.remoting.RPCHook; @@ -57,21 +53,14 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS private final MQClientAPIFactory mqClientAPIFactory; private final TopicRouteService topicRouteService; - private final ScheduledExecutorService scheduledExecutorService; private ThreadPoolExecutor heartbeatExecutors; private final Map/* cluster list */> groupClusterData = new ConcurrentHashMap<>(); private TxHeartbeatServiceThread txHeartbeatServiceThread; - public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, RPCHook rpcHook) { - this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryImpl("ClusterTransactionScheduledThread_")); + public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, RPCHook rpcHook, + MQClientAPIFactory mqClientAPIFactory) { this.topicRouteService = topicRouteService; - this.mqClientAPIFactory = new MQClientAPIFactory( - "ClusterTransaction_", - 1, - new ProxyClientRemotingProcessor(producerManager), - rpcHook, - scheduledExecutorService); + this.mqClientAPIFactory = mqClientAPIFactory; } @Override @@ -182,6 +171,10 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS } } + public Map> getGroupClusterData() { + return groupClusterData; + } + protected void sendHeartBeatToCluster(String clusterName, List heartbeatDataList) { if (heartbeatDataList == null) { return; @@ -220,6 +213,10 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS this.cluster = cluster; } + public String getCluster() { + return cluster; + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -264,7 +261,6 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); txHeartbeatServiceThread = new TxHeartbeatServiceThread(); - mqClientAPIFactory.start(); txHeartbeatServiceThread.start(); heartbeatExecutors = ThreadPoolMonitor.createAndMonitor( proxyConfig.getTransactionHeartbeatThreadPoolNums(), @@ -279,6 +275,5 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS public void shutdown() throws Exception { txHeartbeatServiceThread.shutdown(); heartbeatExecutors.shutdown(); - mqClientAPIFactory.shutdown(); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index 751c62f7c0..c17cca7c2c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -34,17 +34,15 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @Ignore @RunWith(MockitoJUnitRunner.Silent.class) public class BaseActivityTest extends InitConfigAndLoggerTest { protected static final Random RANDOM = new Random(); - @Mock protected MessagingProcessor messagingProcessor; - @Mock protected GrpcClientSettingsManager grpcClientSettingsManager; - @Mock protected ProxyRelayService proxyRelayService; protected static final String REMOTE_ADDR = "192.168.0.1:8080"; @@ -55,6 +53,10 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { public void before() throws Throwable { super.before(); + messagingProcessor = mock(MessagingProcessor.class); + grpcClientSettingsManager = mock(GrpcClientSettingsManager.class); + proxyRelayService = mock(ProxyRelayService.class); + metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java new file mode 100644 index 0000000000..4accbd2e5f --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.client; + +import apache.rocketmq.v2.ClientType; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.FilterExpression; +import apache.rocketmq.v2.FilterType; +import apache.rocketmq.v2.HeartbeatRequest; +import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.NotifyClientTerminationRequest; +import apache.rocketmq.v2.NotifyClientTerminationResponse; +import apache.rocketmq.v2.Publishing; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import apache.rocketmq.v2.SubscriptionEntry; +import apache.rocketmq.v2.TelemetryCommand; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +public class ClientActivityTest extends BaseActivityTest { + + private static final String TOPIC = "topic"; + private static final String CONSUMER_GROUP = "consumerGroup"; + + private ClientActivity clientActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + protected TelemetryCommand sendProducerTelemetry(Context context) throws Throwable { + return this.sendClientTelemetry( + context, + Settings.newBuilder() + .setClientType(ClientType.PRODUCER) + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder().setName(TOPIC).build()) + .build()) + .build()).get(); + } + + protected HeartbeatResponse sendProducerHeartbeat(Context context) throws Throwable { + return this.clientActivity.heartbeat(context, HeartbeatRequest.newBuilder() + .setClientType(ClientType.PRODUCER) + .build()).get(); + } + + @Test + public void testProducerHeartbeat() throws Throwable { + Context context = createContext(); + + this.sendProducerTelemetry(context); + + ArgumentCaptor registerProducerGroupArgumentCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor channelInfoArgumentCaptor = ArgumentCaptor.forClass(ClientChannelInfo.class); + doNothing().when(this.messagingProcessor).registerProducer(any(), + registerProducerGroupArgumentCaptor.capture(), + channelInfoArgumentCaptor.capture()); + + ArgumentCaptor txProducerGroupArgumentCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor txProducerTopicArgumentCaptor = ArgumentCaptor.forClass(String.class); + doNothing().when(this.messagingProcessor).addTransactionSubscription(any(), + txProducerGroupArgumentCaptor.capture(), + txProducerTopicArgumentCaptor.capture() + ); + + HeartbeatResponse response = this.sendProducerHeartbeat(context); + + assertEquals(Code.OK, response.getStatus().getCode()); + + assertEquals(Lists.newArrayList(TOPIC), registerProducerGroupArgumentCaptor.getAllValues()); + ClientChannelInfo clientChannelInfo = channelInfoArgumentCaptor.getValue(); + assertClientChannelInfo(clientChannelInfo, TOPIC); + + assertEquals(Lists.newArrayList(TOPIC), txProducerGroupArgumentCaptor.getAllValues()); + assertEquals(Lists.newArrayList(TOPIC), txProducerTopicArgumentCaptor.getAllValues()); + } + + protected TelemetryCommand sendConsumerTelemetry(Context context) throws Throwable { + return this.sendClientTelemetry( + context, + Settings.newBuilder() + .setClientType(ClientType.PUSH_CONSUMER) + .setSubscription(Subscription.newBuilder() + .addSubscriptions(SubscriptionEntry.newBuilder() + .setExpression(FilterExpression.newBuilder() + .setExpression("tag") + .setType(FilterType.TAG) + .build()) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .build()) + .build()) + .build()).get(); + } + + protected HeartbeatResponse sendConsumerHeartbeat(Context context) throws Throwable { + return this.clientActivity.heartbeat(context, HeartbeatRequest.newBuilder() + .setClientType(ClientType.PUSH_CONSUMER) + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .build()).get(); + } + + @Test + public void testConsumerHeartbeat() throws Throwable { + Context context = createContext(); + this.sendConsumerTelemetry(context); + + ArgumentCaptor> subscriptionDatasArgumentCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor channelInfoArgumentCaptor = ArgumentCaptor.forClass(ClientChannelInfo.class); + doNothing().when(this.messagingProcessor).registerConsumer(any(), + anyString(), + channelInfoArgumentCaptor.capture(), + any(), + any(), + any(), + subscriptionDatasArgumentCaptor.capture() + ); + + + HeartbeatResponse response = this.sendConsumerHeartbeat(context); + assertEquals(Code.OK, response.getStatus().getCode()); + + ClientChannelInfo clientChannelInfo = channelInfoArgumentCaptor.getValue(); + assertClientChannelInfo(clientChannelInfo, CONSUMER_GROUP); + + SubscriptionData data = subscriptionDatasArgumentCaptor.getValue().stream().findAny().get(); + assertEquals("TAG", data.getExpressionType()); + assertEquals("tag", data.getSubString()); + } + + protected void assertClientChannelInfo(ClientChannelInfo clientChannelInfo, String group) { + assertEquals(LanguageCode.JAVA, clientChannelInfo.getLanguage()); + assertEquals(CLIENT_ID, clientChannelInfo.getClientId()); + assertTrue(clientChannelInfo.getChannel() instanceof GrpcClientChannel); + GrpcClientChannel channel = (GrpcClientChannel) clientChannelInfo.getChannel(); + assertEquals(REMOTE_ADDR, channel.getRemoteAddress()); + assertEquals(LOCAL_ADDR, channel.getLocalAddress()); + assertEquals(group, channel.getGroup()); + } + + @Test + public void testProducerNotifyClientTermination() throws Throwable { + Context context = createContext(); + + when(this.grpcClientSettingsManager.removeClientSettings(eq(CLIENT_ID))).thenReturn(Settings.newBuilder() + .setClientType(ClientType.PRODUCER) + .setPublishing(Publishing.newBuilder() + .addTopics(Resource.newBuilder().setName(TOPIC).build()) + .build()) + .build()); + ArgumentCaptor channelInfoArgumentCaptor = ArgumentCaptor.forClass(ClientChannelInfo.class); + doNothing().when(this.messagingProcessor).unRegisterProducer(any(), anyString(), channelInfoArgumentCaptor.capture()); + + this.sendProducerTelemetry(context); + this.sendProducerHeartbeat(context); + + NotifyClientTerminationResponse response = this.clientActivity.notifyClientTermination( + context, + NotifyClientTerminationRequest.newBuilder() + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + ClientChannelInfo clientChannelInfo = channelInfoArgumentCaptor.getValue(); + assertClientChannelInfo(clientChannelInfo, TOPIC); + } + + @Test + public void testConsumerNotifyClientTermination() throws Throwable { + Context context = createContext(); + + when(this.grpcClientSettingsManager.removeClientSettings(eq(CLIENT_ID))).thenReturn(Settings.newBuilder() + .setClientType(ClientType.PUSH_CONSUMER) + .build()); + ArgumentCaptor channelInfoArgumentCaptor = ArgumentCaptor.forClass(ClientChannelInfo.class); + doNothing().when(this.messagingProcessor).unRegisterConsumer(any(), anyString(), channelInfoArgumentCaptor.capture()); + + this.sendConsumerTelemetry(context); + this.sendConsumerHeartbeat(context); + + NotifyClientTerminationResponse response = this.clientActivity.notifyClientTermination( + context, + NotifyClientTerminationRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + ClientChannelInfo clientChannelInfo = channelInfoArgumentCaptor.getValue(); + assertClientChannelInfo(clientChannelInfo, CONSUMER_GROUP); + } + + protected CompletableFuture sendClientTelemetry(Context ctx, Settings settings) { + when(grpcClientSettingsManager.getClientSettings(any())).thenReturn(settings); + + CompletableFuture future = new CompletableFuture<>(); + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(TelemetryCommand value) { + future.complete(value); + } + + @Override + public void onError(Throwable t) { + + } + + @Override public void onCompleted() { + + } + }; + StreamObserver requestObserver = this.clientActivity.telemetry( + ctx, + responseObserver + ); + requestObserver.onNext(TelemetryCommand.newBuilder() + .setSettings(settings) + .build()); + return future; + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java new file mode 100644 index 0000000000..c6153d7133 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java @@ -0,0 +1,64 @@ +/* + * 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.grpc.v2.producer; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; +import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; +import apache.rocketmq.v2.Resource; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +public class ForwardMessageToDLQActivityTest extends BaseActivityTest { + + private ForwardMessageToDLQActivity forwardMessageToDLQActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testForwardMessageToDeadLetterQueue() throws Throwable { + when(this.messagingProcessor.forwardMessageToDeadLetterQueue(any(), any(), anyString(), anyString(), anyString())) + .thenReturn(CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, ""))); + + ForwardMessageToDeadLetterQueueResponse response = this.forwardMessageToDLQActivity.forwardMessageToDeadLetterQueue( + createContext(), + ForwardMessageToDeadLetterQueueRequest.newBuilder() + .setTopic(Resource.newBuilder().setName("topic").build()) + .setGroup(Resource.newBuilder().setName("group").build()) + .setMessageId(MessageClientIDSetter.createUniqID()) + .setReceiptHandle(buildReceiptHandle("topic", System.currentTimeMillis(), 3000)) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java new file mode 100644 index 0000000000..6709ae05ff --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.transaction; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.EndTransactionRequest; +import apache.rocketmq.v2.EndTransactionResponse; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.TransactionResolution; +import apache.rocketmq.v2.TransactionSource; +import java.util.Arrays; +import java.util.Collection; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.processor.TransactionStatus; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.ArgumentCaptor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; + +@RunWith(Parameterized.class) +public class EndTransactionActivityTest extends BaseActivityTest { + + private EndTransactionActivity endTransactionActivity; + private TransactionResolution resolution; + private TransactionSource source; + private TransactionStatus transactionStatus; + private Boolean fromTransactionCheck; + + public EndTransactionActivityTest(TransactionResolution resolution, TransactionSource source, + TransactionStatus transactionStatus, Boolean fromTransactionCheck) { + this.resolution = resolution; + this.source = source; + this.transactionStatus = transactionStatus; + this.fromTransactionCheck = fromTransactionCheck; + } + + @Before + public void before() throws Throwable { + super.before(); + this.endTransactionActivity = new EndTransactionActivity(this.messagingProcessor, this.grpcClientSettingsManager); + } + + @Test + public void testEndTransaction() throws Throwable { + ArgumentCaptor transactionStatusCaptor = ArgumentCaptor.forClass(TransactionStatus.class); + ArgumentCaptor fromTransactionCheckCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing().when(this.messagingProcessor).endTransaction(any(), any(), anyString(), anyString(), + transactionStatusCaptor.capture(), + fromTransactionCheckCaptor.capture()); + + EndTransactionResponse response = this.endTransactionActivity.endTransaction( + createContext(), + EndTransactionRequest.newBuilder() + .setResolution(resolution) + .setTopic(Resource.newBuilder().setName("topic").build()) + .setMessageId(MessageClientIDSetter.createUniqID()) + .setTransactionId( + TransactionId.genByBrokerTransactionId("brokerName", "0", 0, 0) + .getProxyTransactionId()) + .setSource(source) + .build() + ).get(); + + assertEquals(Code.OK, response.getStatus().getCode()); + assertEquals(transactionStatus, transactionStatusCaptor.getValue()); + assertEquals(fromTransactionCheck, fromTransactionCheckCaptor.getValue()); + } + + @Parameterized.Parameters + public static Collection parameters() { + Object[][] p = new Object[][]{ + {TransactionResolution.COMMIT, TransactionSource.SOURCE_CLIENT, TransactionStatus.COMMIT, false}, + {TransactionResolution.ROLLBACK, TransactionSource.SOURCE_SERVER_CHECK, TransactionStatus.ROLLBACK, true}, + {TransactionResolution.TRANSACTION_RESOLUTION_UNSPECIFIED, TransactionSource.SOURCE_SERVER_CHECK, TransactionStatus.UNKNOWN, true}, + }; + return Arrays.asList(p); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/BaseServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/BaseServiceTest.java new file mode 100644 index 0000000000..f6ca31ff84 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/BaseServiceTest.java @@ -0,0 +1,83 @@ +/* + * 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.service; + +import java.util.HashMap; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIExt; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.TopicRouteService; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@Ignore +@RunWith(MockitoJUnitRunner.Silent.class) +public class BaseServiceTest extends InitConfigAndLoggerTest { + + protected TopicRouteService topicRouteService; + protected MQClientAPIFactory mqClientAPIFactory; + protected MQClientAPIExt mqClientAPIExt; + + protected static final String ERR_TOPIC = "errTopic"; + protected static final String TOPIC = "topic"; + protected static final String GROUP = "group"; + protected static final String BROKER_NAME = "broker"; + protected static final String CLUSTER_NAME = "cluster"; + protected static final String BROKER_ADDR = "127.0.0.1:10911"; + + protected final TopicRouteData topicRouteData = new TopicRouteData(); + protected final QueueData queueData = new QueueData(); + protected final BrokerData brokerData = new BrokerData(); + + @Before + public void before() throws Throwable { + super.before(); + + topicRouteService = mock(TopicRouteService.class); + mqClientAPIFactory = mock(MQClientAPIFactory.class); + mqClientAPIExt = mock(MQClientAPIExt.class); + when(mqClientAPIFactory.getClient()).thenReturn(mqClientAPIExt); + + queueData.setBrokerName(BROKER_NAME); + topicRouteData.setQueueDatas(Lists.newArrayList(queueData)); + brokerData.setCluster(CLUSTER_NAME); + brokerData.setBrokerName(BROKER_NAME); + HashMap brokerAddrs = new HashMap<>(); + brokerAddrs.put(MixAll.MASTER_ID, BROKER_ADDR); + brokerData.setBrokerAddrs(brokerAddrs); + topicRouteData.setBrokerDatas(Lists.newArrayList(brokerData)); + + when(this.topicRouteService.getAllMessageQueueView(eq(ERR_TOPIC))).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + when(this.topicRouteService.getAllMessageQueueView(eq(TOPIC))).thenReturn(new MessageQueueView(TOPIC, topicRouteData)); + when(this.topicRouteService.getAllMessageQueueView(eq(CLUSTER_NAME))).thenReturn(new MessageQueueView(CLUSTER_NAME, topicRouteData)); + } +} diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java new file mode 100644 index 0000000000..7eeb72060e --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java @@ -0,0 +1,73 @@ +/* + * 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.service.metadata; + +import java.util.HashMap; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.service.BaseServiceTest; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class ClusterMetadataServiceTest extends BaseServiceTest { + + private ClusterMetadataService clusterMetadataService; + + @Before + public void before() throws Throwable { + super.before(); + ConfigurationManager.getProxyConfig().setRocketMQClusterName(CLUSTER_NAME); + + TopicConfigAndQueueMapping topicConfigAndQueueMapping = new TopicConfigAndQueueMapping(); + topicConfigAndQueueMapping.setAttributes(new HashMap<>()); + topicConfigAndQueueMapping.setTopicMessageType(TopicMessageType.NORMAL); + when(this.mqClientAPIExt.getTopicConfig(anyString(), eq(TOPIC), anyLong())).thenReturn(topicConfigAndQueueMapping); + + when(this.mqClientAPIExt.getSubscriptionGroupConfig(anyString(), eq(GROUP), anyLong())).thenReturn(new SubscriptionGroupConfig()); + + this.clusterMetadataService = new ClusterMetadataService(this.topicRouteService, this.mqClientAPIFactory); + } + + @Test + public void testGetTopicMessageType() { + assertEquals(TopicMessageType.UNSPECIFIED, this.clusterMetadataService.getTopicMessageType(ERR_TOPIC)); + assertEquals(1, this.clusterMetadataService.topicConfigCache.asMap().size()); + assertEquals(TopicMessageType.UNSPECIFIED, this.clusterMetadataService.getTopicMessageType(ERR_TOPIC)); + + assertEquals(TopicMessageType.NORMAL, this.clusterMetadataService.getTopicMessageType(TOPIC)); + assertEquals(2, this.clusterMetadataService.topicConfigCache.asMap().size()); + } + + @Test + public void testGetSubscriptionGroupConfig() { + assertNotNull(this.clusterMetadataService.getSubscriptionGroupConfig(GROUP)); + assertEquals(1, this.clusterMetadataService.subscriptionGroupConfigCache.asMap().size()); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java new file mode 100644 index 0000000000..2d5f64de37 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.route; + +import com.google.common.net.HostAndPort; +import java.util.ArrayList; +import java.util.List; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.proxy.service.BaseServiceTest; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.catchThrowableOfType; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class ClusterTopicRouteServiceTest extends BaseServiceTest { + + private ClusterTopicRouteService topicRouteService; + + @Before + public void before() throws Throwable { + super.before(); + this.topicRouteService = new ClusterTopicRouteService(this.mqClientAPIFactory); + + when(this.mqClientAPIExt.getTopicRouteInfoFromNameServer(eq(TOPIC), anyLong())).thenReturn(topicRouteData); + when(this.mqClientAPIExt.getTopicRouteInfoFromNameServer(eq(ERR_TOPIC), anyLong())).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + } + + @Test + public void testGetCurrentMessageQueueView() throws Throwable { + MQClientException exception = catchThrowableOfType(() -> this.topicRouteService.getCurrentMessageQueueView(ERR_TOPIC), MQClientException.class); + assertTrue(TopicRouteHelper.isTopicNotExistError(exception)); + assertEquals(1, this.topicRouteService.topicCache.asMap().size()); + + assertNotNull(this.topicRouteService.getCurrentMessageQueueView(TOPIC)); + assertEquals(2, this.topicRouteService.topicCache.asMap().size()); + } + + @Test + public void testGetTopicRouteForProxy() throws Throwable { + List
addressList = Lists.newArrayList(new Address(Address.AddressScheme.IPv4, HostAndPort.fromParts("127.0.0.1", 8888))); + ProxyTopicRouteData proxyTopicRouteData = this.topicRouteService.getTopicRouteForProxy(addressList, TOPIC); + + assertEquals(1, proxyTopicRouteData.getBrokerDatas().size()); + assertEquals(addressList, proxyTopicRouteData.getBrokerDatas().get(0).getBrokerAddrs().get(MixAll.MASTER_ID)); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteServiceTest.java new file mode 100644 index 0000000000..709d6cc04c --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/LocalTopicRouteServiceTest.java @@ -0,0 +1,102 @@ +/* + * 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.service.route; + +import com.google.common.net.HostAndPort; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.topic.TopicConfigManager; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.BrokerConfig; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.common.Address; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.service.BaseServiceTest; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class LocalTopicRouteServiceTest extends BaseServiceTest { + + private static final String LOCAL_BROKER_NAME = "localBroker"; + private static final String LOCAL_CLUSTER_NAME = "localCluster"; + private static final String LOCAL_HOST = "127.0.0.2"; + private static final int LOCAL_PORT = 10911; + private static final String LOCAL_ADDR = LOCAL_HOST + ":" + LOCAL_PORT; + @Mock + private BrokerController brokerController; + @Mock + private TopicConfigManager topicConfigManager; + private ConcurrentMap topicConfigTable = new ConcurrentHashMap<>(); + private BrokerConfig brokerConfig = new BrokerConfig(); + private LocalTopicRouteService topicRouteService; + + @Before + public void before() throws Throwable { + super.before(); + this.brokerConfig.setBrokerName(LOCAL_BROKER_NAME); + this.brokerConfig.setBrokerClusterName(LOCAL_CLUSTER_NAME); + + when(this.brokerController.getBrokerAddr()).thenReturn(LOCAL_ADDR); + when(this.brokerController.getBrokerConfig()).thenReturn(this.brokerConfig); + when(this.brokerController.getTopicConfigManager()).thenReturn(this.topicConfigManager); + when(this.topicConfigManager.getTopicConfigTable()).thenReturn(this.topicConfigTable); + + this.topicRouteService = new LocalTopicRouteService(this.brokerController, this.mqClientAPIFactory); + + when(this.mqClientAPIExt.getTopicRouteInfoFromNameServer(eq(TOPIC), anyLong())).thenReturn(topicRouteData); + when(this.mqClientAPIExt.getTopicRouteInfoFromNameServer(eq(ERR_TOPIC), anyLong())).thenThrow(new MQClientException(ResponseCode.TOPIC_NOT_EXIST, "")); + } + + @Test + public void testGetCurrentMessageQueueView() throws Throwable { + this.topicConfigTable.put(TOPIC, new TopicConfig(TOPIC, 3, 2, PermName.PERM_WRITE | PermName.PERM_READ)); + MessageQueueView messageQueueView = this.topicRouteService.getCurrentMessageQueueView(TOPIC); + assertEquals(3, messageQueueView.getReadSelector().getQueues().size()); + assertEquals(2, messageQueueView.getWriteSelector().getQueues().size()); + assertEquals(1, messageQueueView.getReadSelector().getBrokerActingQueues().size()); + assertEquals(1, messageQueueView.getWriteSelector().getBrokerActingQueues().size()); + + assertEquals(LOCAL_ADDR, messageQueueView.getReadSelector().selectOne(true).getBrokerAddr()); + assertEquals(LOCAL_BROKER_NAME, messageQueueView.getReadSelector().selectOne(true).getBrokerName()); + assertEquals(messageQueueView.getReadSelector().selectOne(true), messageQueueView.getWriteSelector().selectOne(true)); + } + + @Test + public void testGetTopicRouteForProxy() throws Throwable { + ProxyTopicRouteData proxyTopicRouteData = this.topicRouteService.getTopicRouteForProxy(new ArrayList<>(), TOPIC); + + assertEquals(1, proxyTopicRouteData.getBrokerDatas().size()); + assertEquals( + Lists.newArrayList(new Address(Address.AddressScheme.IPv4, HostAndPort.fromParts( + HostAndPort.fromString(BROKER_ADDR).getHost(), + ConfigurationManager.getProxyConfig().getGrpcServerPort()))), + proxyTopicRouteData.getBrokerDatas().get(0).getBrokerAddrs().get(MixAll.MASTER_ID)); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java new file mode 100644 index 0000000000..a59c4cf20a --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java @@ -0,0 +1,84 @@ +/* + * 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.service.route; + +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.proxy.service.BaseServiceTest; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class MessageQueueSelectorTest extends BaseServiceTest { + + @Test + public void testReadMessageQueue() { + queueData.setPerm(PermName.PERM_READ); + queueData.setReadQueueNums(0); + MessageQueueSelector messageQueueSelector = new MessageQueueSelector(new TopicRouteWrapper(topicRouteData, TOPIC), true); + assertTrue(messageQueueSelector.getQueues().isEmpty()); + + queueData.setPerm(PermName.PERM_READ); + queueData.setReadQueueNums(3); + messageQueueSelector = new MessageQueueSelector(new TopicRouteWrapper(topicRouteData, TOPIC), true); + assertEquals(3, messageQueueSelector.getQueues().size()); + assertEquals(1, messageQueueSelector.getBrokerActingQueues().size()); + for (int i = 0; i < messageQueueSelector.getQueues().size(); i++) { + SelectableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); + assertEquals(i, messageQueue.getQueueId()); + } + + SelectableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); + assertEquals(brokerQueue, messageQueueSelector.getBrokerActingQueues().get(0)); + assertEquals(brokerQueue, messageQueueSelector.selectOne(true)); + assertEquals(brokerQueue, messageQueueSelector.selectOneByIndex(3, true)); + + SelectableMessageQueue queue = messageQueueSelector.selectOne(false); + messageQueueSelector.selectOne(false); + messageQueueSelector.selectOne(false); + assertEquals(queue, messageQueueSelector.selectOne(false)); + } + + @Test + public void testWriteMessageQueue() { + queueData.setPerm(PermName.PERM_WRITE); + queueData.setReadQueueNums(0); + MessageQueueSelector messageQueueSelector = new MessageQueueSelector(new TopicRouteWrapper(topicRouteData, TOPIC), false); + assertTrue(messageQueueSelector.getQueues().isEmpty()); + + queueData.setPerm(PermName.PERM_WRITE); + queueData.setWriteQueueNums(3); + messageQueueSelector = new MessageQueueSelector(new TopicRouteWrapper(topicRouteData, TOPIC), false); + assertEquals(3, messageQueueSelector.getQueues().size()); + assertEquals(1, messageQueueSelector.getBrokerActingQueues().size()); + for (int i = 0; i < messageQueueSelector.getQueues().size(); i++) { + SelectableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); + assertEquals(i, messageQueue.getQueueId()); + } + + SelectableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); + assertEquals(brokerQueue, messageQueueSelector.getBrokerActingQueues().get(0)); + assertEquals(brokerQueue, messageQueueSelector.selectOne(true)); + assertEquals(brokerQueue, messageQueueSelector.selectOneByIndex(3, true)); + + SelectableMessageQueue queue = messageQueueSelector.selectOne(false); + messageQueueSelector.selectOne(false); + messageQueueSelector.selectOne(false); + assertEquals(queue, messageQueueSelector.selectOne(false)); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java new file mode 100644 index 0000000000..517838f42c --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java @@ -0,0 +1,141 @@ +/* + * 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.service.transaction; + +import java.time.Duration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.service.BaseServiceTest; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + + +public class ClusterTransactionServiceTest extends BaseServiceTest { + + @Mock + private ProducerManager producerManager; + + private ClusterTransactionService clusterTransactionService; + + @Before + public void before() throws Throwable { + super.before(); + this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, null, + this.mqClientAPIFactory); + + MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData); + when(this.topicRouteService.getAllMessageQueueView(anyString())) + .thenReturn(messageQueueView); + + when(mqClientAPIFactory.getClient()).thenReturn(mqClientAPIExt); + } + + @Test + public void testAddTransactionSubscription() { + this.clusterTransactionService.addTransactionSubscription(GROUP, TOPIC); + + assertEquals(1, this.clusterTransactionService.getGroupClusterData().size()); + assertEquals(CLUSTER_NAME, this.clusterTransactionService.getGroupClusterData().get(GROUP).stream().findAny().get().getCluster()); + } + + @Test + public void testAddTransactionSubscriptionTopicList() { + this.clusterTransactionService.addTransactionSubscription(GROUP, Lists.newArrayList(TOPIC + 1, TOPIC + 2)); + + assertEquals(1, this.clusterTransactionService.getGroupClusterData().size()); + assertEquals(CLUSTER_NAME, this.clusterTransactionService.getGroupClusterData().get(GROUP).stream().findAny().get().getCluster()); + } + + @Test + public void testReplaceTransactionSubscription() { + this.clusterTransactionService.addTransactionSubscription(GROUP, TOPIC); + + assertEquals(1, this.clusterTransactionService.getGroupClusterData().size()); + assertEquals(CLUSTER_NAME, this.clusterTransactionService.getGroupClusterData().get(GROUP).stream().findAny().get().getCluster()); + + this.brokerData.setCluster(CLUSTER_NAME + 1); + this.clusterTransactionService.replaceTransactionSubscription(GROUP, Lists.newArrayList(TOPIC + 1)); + assertEquals(1, this.clusterTransactionService.getGroupClusterData().size()); + assertEquals(CLUSTER_NAME + 1, this.clusterTransactionService.getGroupClusterData().get(GROUP).stream().findAny().get().getCluster()); + } + + @Test + public void testUnSubscribeAllTransactionTopic() { + this.clusterTransactionService.addTransactionSubscription(GROUP, TOPIC); + this.clusterTransactionService.unSubscribeAllTransactionTopic(GROUP); + + assertEquals(0, this.clusterTransactionService.getGroupClusterData().size()); + } + + @Test + public void testScanProducerHeartBeat() throws Exception { + ConfigurationManager.getProxyConfig().setTransactionHeartbeatBatchNum(2); + this.clusterTransactionService.start(); + Set groupSet = new HashSet<>(); + + for (int i = 0; i < 3; i++) { + groupSet.add(GROUP + i); + this.clusterTransactionService.addTransactionSubscription(GROUP + i, TOPIC); + } + + ArgumentCaptor brokerAddrArgumentCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor heartbeatDataArgumentCaptor = ArgumentCaptor.forClass(HeartbeatData.class); + doNothing().when(mqClientAPIExt).sendHeartbeatOneway( + brokerAddrArgumentCaptor.capture(), + heartbeatDataArgumentCaptor.capture(), + anyLong() + ); + + this.clusterTransactionService.scanProducerHeartBeat(); + + await().atMost(Duration.ofSeconds(1)).until(() -> brokerAddrArgumentCaptor.getAllValues().size() == 2); + + assertEquals(Lists.newArrayList(BROKER_ADDR, BROKER_ADDR), brokerAddrArgumentCaptor.getAllValues()); + List heartbeatDataList = heartbeatDataArgumentCaptor.getAllValues(); + assertEquals(2, heartbeatDataList.get(0).getProducerDataSet().size()); + for (ProducerData producerData : heartbeatDataList.get(0).getProducerDataSet()) { + groupSet.remove(producerData.getGroupName()); + } + + assertEquals(1, heartbeatDataList.get(1).getProducerDataSet().size()); + for (ProducerData producerData : heartbeatDataList.get(1).getProducerDataSet()) { + groupSet.remove(producerData.getGroupName()); + } + + assertTrue(groupSet.isEmpty()); + } +} \ No newline at end of file From 2fe29957cbe5baab2aa1180997b7ae26f12047d8 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 24 May 2022 12:27:20 +0800 Subject: [PATCH 200/338] [ISSUE #3949] for checkstyle --- .../rocketmq/proxy/grpc/v2/consumer/AckMessageActivity.java | 1 - 1 file changed, 1 deletion(-) 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 65c4f4fb3d..42cc3a8645 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 @@ -36,7 +36,6 @@ 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.MessagingProcessor; -import org.checkerframework.checker.units.qual.C; public class AckMessageActivity extends AbstractMessingActivity { From 1fa561cb94887923f99cf04798237f0eac6b39e3 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 24 May 2022 14:24:57 +0800 Subject: [PATCH 201/338] [ISSUE #3949] Add TopicMessageTypeValidator --- .../proxy/common/ContextVariable.java | 1 + .../proxy/common/ProxyExceptionCode.java | 1 + .../proxy/grpc/v2/common/GrpcConverter.java | 15 ++++++++ .../grpc/v2/producer/SendMessageActivity.java | 25 ++++++++++++- .../proxy/processor/ProducerProcessor.java | 36 +++++++++++++------ .../DefaultTopicMessageTypeValidator.java | 31 ++++++++++++++++ .../validator/TopicMessageTypeValidator.java | 29 +++++++++++++++ 7 files changed, 126 insertions(+), 12 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index fcc6bb02ff..f77ad376f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -20,4 +20,5 @@ package org.apache.rocketmq.proxy.common; public class ContextVariable { public final static String REMOTE_ADDRESS = "remote-address"; public final static String LOCAL_ADDRESS = "local-address"; + public final static String MESSAGE_TYPE = "message-type"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 2fbe49ef43..50a5ce1353 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -23,4 +23,5 @@ public enum ProxyExceptionCode { INVALID_RECEIPT_HANDLE, ILLEGAL_MESSAGE, INTERNAL_SERVER_ERROR, + TOPIC_MESSAGE_TYPE_NOT_MATCH, } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 72db47eccf..04169146b0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -35,6 +35,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; @@ -229,4 +230,18 @@ public class GrpcConverter { .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) .build(); } + + public static TopicMessageType buildTopicMessageType(MessageType messageType) { + if (messageType.equals(MessageType.NORMAL)) { + return TopicMessageType.NORMAL; + } else if (messageType.equals(MessageType.FIFO)) { + return TopicMessageType.FIFO; + } else if (messageType.equals(MessageType.DELAY)) { + return TopicMessageType.DELAY; + } else if (messageType.equals(MessageType.TRANSACTION)) { + return TopicMessageType.TRANSACTION; + } else { + return TopicMessageType.UNSPECIFIED; + } + } } 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 998c0276fb..59bbb0ea0b 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 @@ -40,11 +40,15 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ContextVariable; 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.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; @@ -52,14 +56,18 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; +import org.apache.rocketmq.proxy.processor.validator.DefaultTopicMessageTypeValidator; +import org.apache.rocketmq.proxy.processor.validator.TopicMessageTypeValidator; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; public class SendMessageActivity extends AbstractMessingActivity { + private final TopicMessageTypeValidator validator; public SendMessageActivity(MessagingProcessor messagingProcessor, GrpcClientSettingsManager grpcClientSettingsManager) { super(messagingProcessor, grpcClientSettingsManager); + this.validator = new DefaultTopicMessageTypeValidator(); } public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { @@ -71,10 +79,13 @@ public class SendMessageActivity extends AbstractMessingActivity { throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } + MessageType messageType = parseMessageType(request.getMessagesList()); + TopicMessageType topicMessageType = GrpcConverter.buildTopicMessageType(messageType); + List messageList = request.getMessagesList(); Resource topic = messageList.get(0).getTopic(); future = this.messagingProcessor.sendMessage( - context, + context.withVal(ContextVariable.MESSAGE_TYPE, topicMessageType.getValue()), new SendMessageQueueSelector(request), GrpcConverter.wrapResourceWithNamespace(topic), buildMessage(context, request.getMessagesList(), topic) @@ -241,6 +252,18 @@ public class SendMessageActivity extends AbstractMessingActivity { return builder.build(); } + protected MessageType parseMessageType(List messageList) { + MessageType messageType = messageList.get(0).getSystemProperties().getMessageType(); + for (Message message : messageList) { + MessageType messageType0 = message.getSystemProperties().getMessageType(); + if (messageType0 != messageType) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE, "message type is not match"); + } + messageType = messageType0; + } + return messageType; + } + protected static class SendMessageQueueSelector implements QueueSelector { private final SendMessageRequest request; 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 a5baf4f9a5..b93187380a 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 @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; @@ -32,10 +33,14 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ContextVariable; 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.utils.FutureUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.processor.validator.DefaultTopicMessageTypeValidator; +import org.apache.rocketmq.proxy.processor.validator.TopicMessageTypeValidator; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -44,11 +49,13 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerProcessor extends AbstractProcessor { private final ExecutorService executor; + private final TopicMessageTypeValidator topicMessageTypeValidator; public ProducerProcessor(MessagingProcessor messagingProcessor, ServiceManager serviceManager, ExecutorService executor) { super(messagingProcessor, serviceManager); this.executor = executor; + this.topicMessageTypeValidator = new DefaultTopicMessageTypeValidator(); } public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector, @@ -56,6 +63,13 @@ public class ProducerProcessor extends AbstractProcessor { CompletableFuture> future = new CompletableFuture<>(); try { String topic = messageExtList.get(0).getTopic(); + if (ConfigurationManager.getProxyConfig().isEnableTopicMessageTypeCheck()) { + if (topicMessageTypeValidator != null) { + TopicMessageType topicMessageType = serviceManager.getMetadataService().getTopicMessageType(topic); + TopicMessageType messageType = TopicMessageType.valueOf(ctx.getVal(ContextVariable.MESSAGE_TYPE)); + topicMessageTypeValidator.validate(topicMessageType, messageType); + } + } SelectableMessageQueue messageQueue = queueSelector.select(ctx, this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); if (messageQueue == null) { @@ -70,18 +84,18 @@ public class ProducerProcessor extends AbstractProcessor { messageExtList, requestHeader, timeoutMillis) - .thenApplyAsync(sendResultList -> { - for (SendResult sendResult : sendResultList) { - int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && - tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && - StringUtils.isNotBlank(sendResult.getTransactionId())) { - TransactionId transactionId = TransactionId.genByBrokerTransactionId(messageQueue.getBrokerName(), sendResult); - sendResult.setTransactionId(transactionId.getProxyTransactionId()); + .thenApplyAsync(sendResultList -> { + for (SendResult sendResult : sendResultList) { + int tranType = MessageSysFlag.getTransactionValue(requestHeader.getSysFlag()); + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && + tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && + StringUtils.isNotBlank(sendResult.getTransactionId())) { + TransactionId transactionId = TransactionId.genByBrokerTransactionId(messageQueue.getBrokerName(), sendResult); + sendResult.setTransactionId(transactionId.getProxyTransactionId()); + } } - } - return sendResultList; - }, this.executor); + return sendResultList; + }, this.executor); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java new file mode 100644 index 0000000000..a0718c5ced --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.processor.validator; + +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.proxy.common.ProxyException; +import org.apache.rocketmq.proxy.common.ProxyExceptionCode; + +public class DefaultTopicMessageTypeValidator implements TopicMessageTypeValidator { + + public void validate(TopicMessageType topicMessageType, TopicMessageType messageType) { + if (messageType.equals(TopicMessageType.UNSPECIFIED) || !messageType.equals(topicMessageType)) { + throw new ProxyException(ProxyExceptionCode.TOPIC_MESSAGE_TYPE_NOT_MATCH, messageType.name() + " " + topicMessageType.name()); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java new file mode 100644 index 0000000000..43eae1e314 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.processor.validator; + +import org.apache.rocketmq.common.attribute.TopicMessageType; + +public interface TopicMessageTypeValidator { + /** + * Will throw {@link org.apache.rocketmq.proxy.common.ProxyException} if validate failed. + * @param topicMessageType Target topic + * @param messageType Message's type + */ + void validate(TopicMessageType topicMessageType, TopicMessageType messageType); +} From aa313e96f8adb22554583fb691ac9ebc00120283 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 24 May 2022 14:51:37 +0800 Subject: [PATCH 202/338] [ISSUE #3949] Optimize enableACL configuration --- .../proxy/grpc/GrpcServerBuilder.java | 7 +-- .../AuthenticationInterceptor.java | 45 ++++++++++--------- 2 files changed, 27 insertions(+), 25 deletions(-) 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 bd72629814..e380db3439 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 @@ -142,11 +142,8 @@ public class GrpcServerBuilder { public GrpcServerBuilder configInterceptor() { // grpc interceptors, including acl, logging etc. - if (ConfigurationManager.getProxyConfig().isEnableACL()) { - List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); - if (accessValidators.isEmpty()) { - throw new IllegalArgumentException("Load AccessValidator failed"); - } + List accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessValidator.class); + if (!accessValidators.isEmpty()) { this.serverBuilder.intercept(new AuthenticationInterceptor(accessValidators)); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index 409c2c8c16..5d3fc0f105 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -32,6 +32,7 @@ import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.MetadataHeader; import org.apache.rocketmq.acl.plain.PlainAccessResource; +import org.apache.rocketmq.proxy.config.ConfigurationManager; public class AuthenticationInterceptor implements ServerInterceptor { private final List accessValidatorList; @@ -46,28 +47,32 @@ public class AuthenticationInterceptor implements ServerInterceptor { return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { @Override public void onMessage(R message) { - try { - GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; - MetadataHeader metadataHeader = MetadataHeader.builder() - .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) - .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) - .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) - .datetime(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.DATE_TIME)) - .sessionToken(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.SESSION_TOKEN)) - .requestId(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REQUEST_ID)) - .language(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE)) - .clientVersion(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.CLIENT_VERSION)) - .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) - .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) - .build(); - for (AccessValidator accessValidator : accessValidatorList) { - AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); - accessValidator.validate(accessResource); - addHeader(headers, messageV3, accessResource); + if (ConfigurationManager.getProxyConfig().isEnableACL()) { + try { + GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; + MetadataHeader metadataHeader = MetadataHeader.builder() + .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) + .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) + .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) + .datetime(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.DATE_TIME)) + .sessionToken(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.SESSION_TOKEN)) + .requestId(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REQUEST_ID)) + .language(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.LANGUAGE)) + .clientVersion(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.CLIENT_VERSION)) + .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) + .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) + .build(); + for (AccessValidator accessValidator : accessValidatorList) { + AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); + accessValidator.validate(accessResource); + addHeader(headers, messageV3, accessResource); + } + super.onMessage(message); + } catch (AclException aclException) { + throw new StatusRuntimeException(Status.PERMISSION_DENIED, headers); } + } else { super.onMessage(message); - } catch (AclException aclException) { - throw new StatusRuntimeException(Status.PERMISSION_DENIED, headers); } } }; From cc827021c464776f4af330f428229dffa683385f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 24 May 2022 15:06:29 +0800 Subject: [PATCH 203/338] [ISSUE #3949] add test cases --- .../subscription/CustomizedRetryPolicy.java | 7 + .../subscription/ExponentialRetryPolicy.java | 9 ++ .../grpc/v2/channel/GrpcClientChannel.java | 12 -- .../proxy/grpc/v2/client/ClientActivity.java | 2 +- .../v2/common/GrpcClientSettingsManager.java | 17 +- .../proxy/service/relay/ProxyChannel.java | 17 ++ .../grpc/v2/client/ClientActivityTest.java | 5 +- .../common/GrpcClientSettingsManagerTest.java | 98 ++++++++++++ .../proxy/service/relay/ProxyChannelTest.java | 150 ++++++++++++++++++ 9 files changed, 299 insertions(+), 18 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java diff --git a/common/src/main/java/org/apache/rocketmq/common/subscription/CustomizedRetryPolicy.java b/common/src/main/java/org/apache/rocketmq/common/subscription/CustomizedRetryPolicy.java index 1fe1983f32..c15e16c546 100644 --- a/common/src/main/java/org/apache/rocketmq/common/subscription/CustomizedRetryPolicy.java +++ b/common/src/main/java/org/apache/rocketmq/common/subscription/CustomizedRetryPolicy.java @@ -48,6 +48,13 @@ public class CustomizedRetryPolicy implements RetryPolicy { TimeUnit.HOURS.toMillis(2) }; + public CustomizedRetryPolicy() { + } + + public CustomizedRetryPolicy(long[] next) { + this.next = next; + } + public long[] getNext() { return next; } diff --git a/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java b/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java index f1c15e2967..04f654a6e6 100644 --- a/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java +++ b/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java @@ -28,6 +28,15 @@ public class ExponentialRetryPolicy implements RetryPolicy { private long max = TimeUnit.HOURS.toMillis(2); private long multiplier = 2; + public ExponentialRetryPolicy() { + } + + public ExponentialRetryPolicy(long initial, long max, long multiplier) { + this.initial = initial; + this.max = max; + this.multiplier = multiplier; + } + public long getInitial() { return initial; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 2f629db4cd..2f25483041 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -24,7 +24,6 @@ import com.google.common.collect.ComparisonChain; import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.ChannelId; -import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.common.message.MessageExt; @@ -39,7 +38,6 @@ import org.apache.rocketmq.proxy.service.relay.ProxyChannel; import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.transaction.TransactionId; -import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends ProxyChannel { @@ -117,16 +115,6 @@ public class GrpcClientChannel extends ProxyChannel { return this.telemetryCommandRef.get() != null; } - @Override - protected SocketAddress localAddress0() { - return RemotingUtil.string2SocketAddress(this.localAddress); - } - - @Override - protected SocketAddress remoteAddress0() { - return RemotingUtil.string2SocketAddress(this.remoteAddress); - } - @Override protected CompletableFuture processOtherMessage(Object msg) { if (msg instanceof TelemetryCommand) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index e4a4e60918..5b149288cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -153,7 +153,7 @@ public class ClientActivity extends AbstractMessingActivity { ProxyContext context = createContext(ctx); String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); - Settings clientSettings = grpcClientSettingsManager.removeClientSettings(clientId); + Settings clientSettings = grpcClientSettingsManager.removeAndGetClientSettings(context); switch (clientSettings.getClientType()) { case PRODUCER: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index 834a4d37b9..f2cd66a43e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -75,6 +75,9 @@ public class GrpcClientSettingsManager { public Settings getClientSettings(ProxyContext ctx) { String clientId = ctx.getVal(GrpcContextConstants.CLIENT_ID); Settings settings = CLIENT_SETTINGS_MAP.get(clientId); + if (settings == null) { + return null; + } if (settings.hasSubscription()) { settings = mergeSubscriptionData(ctx, settings, GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup())); @@ -141,7 +144,17 @@ public class GrpcClientSettingsManager { CLIENT_SETTINGS_MAP.put(clientId, settings); } - public Settings removeClientSettings(String clientId) { - return CLIENT_SETTINGS_MAP.remove(clientId); + public void removeClientSettings(String clientId) { + CLIENT_SETTINGS_MAP.remove(clientId); + } + + public Settings removeAndGetClientSettings(ProxyContext ctx) { + String clientId = ctx.getVal(GrpcContextConstants.CLIENT_ID); + Settings settings = CLIENT_SETTINGS_MAP.remove(clientId); + if (settings == null) { + return null; + } + return mergeSubscriptionData(ctx, settings, + GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup())); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 157bcd63ba..54bf8d0a7d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -44,12 +44,15 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public abstract class ProxyChannel extends AbstractChannel { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final String remoteAddress; + protected final SocketAddress remoteSocketAddress; protected final String localAddress; + protected final SocketAddress localSocketAddress; protected final ProxyRelayService proxyRelayService; @@ -57,14 +60,18 @@ public abstract class ProxyChannel extends AbstractChannel { super(parent); this.proxyRelayService = proxyRelayService; this.remoteAddress = remoteAddress; + this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); this.localAddress = localAddress; + this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, String localAddress) { super(parent, id); this.proxyRelayService = proxyRelayService; this.remoteAddress = remoteAddress; + this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); this.localAddress = localAddress; + this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } @Override @@ -179,4 +186,14 @@ public abstract class ProxyChannel extends AbstractChannel { protected void doWrite(ChannelOutboundBuffer in) throws Exception { } + + @Override + protected SocketAddress localAddress0() { + return this.localSocketAddress; + } + + @Override + protected SocketAddress remoteAddress0() { + return this.remoteSocketAddress; + } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index 4accbd2e5f..f8597c3f32 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -49,7 +49,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @@ -180,7 +179,7 @@ public class ClientActivityTest extends BaseActivityTest { public void testProducerNotifyClientTermination() throws Throwable { Context context = createContext(); - when(this.grpcClientSettingsManager.removeClientSettings(eq(CLIENT_ID))).thenReturn(Settings.newBuilder() + when(this.grpcClientSettingsManager.removeAndGetClientSettings(any())).thenReturn(Settings.newBuilder() .setClientType(ClientType.PRODUCER) .setPublishing(Publishing.newBuilder() .addTopics(Resource.newBuilder().setName(TOPIC).build()) @@ -207,7 +206,7 @@ public class ClientActivityTest extends BaseActivityTest { public void testConsumerNotifyClientTermination() throws Throwable { Context context = createContext(); - when(this.grpcClientSettingsManager.removeClientSettings(eq(CLIENT_ID))).thenReturn(Settings.newBuilder() + when(this.grpcClientSettingsManager.removeAndGetClientSettings(any())).thenReturn(Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) .build()); ArgumentCaptor channelInfoArgumentCaptor = ArgumentCaptor.forClass(ClientChannelInfo.class); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java new file mode 100644 index 0000000000..056eeb4018 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java @@ -0,0 +1,98 @@ +/* + * 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.grpc.v2.common; + +import apache.rocketmq.v2.CustomizedBackoff; +import apache.rocketmq.v2.ExponentialBackoff; +import apache.rocketmq.v2.Resource; +import apache.rocketmq.v2.RetryPolicy; +import apache.rocketmq.v2.Settings; +import apache.rocketmq.v2.Subscription; +import com.google.protobuf.util.Durations; +import org.apache.rocketmq.common.subscription.CustomizedRetryPolicy; +import org.apache.rocketmq.common.subscription.ExponentialRetryPolicy; +import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +public class GrpcClientSettingsManagerTest extends BaseActivityTest { + private GrpcClientSettingsManager grpcClientSettingsManager; + + @Before + public void before() throws Throwable { + super.before(); + this.grpcClientSettingsManager = new GrpcClientSettingsManager(this.messagingProcessor); + } + + @Test + public void testGetSubscriptionData() { + SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig(); + when(this.messagingProcessor.getSubscriptionGroupConfig(any(), any())) + .thenReturn(subscriptionGroupConfig); + + this.grpcClientSettingsManager.updateClientSettings(CLIENT_ID, Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setGroup(Resource.newBuilder().setName("group").build()) + .build()) + .build()); + + ProxyContext context = ProxyContext.create().withVal(GrpcContextConstants.CLIENT_ID, CLIENT_ID); + + Settings settings = this.grpcClientSettingsManager.getClientSettings(context); + assertEquals(settings.getBackoffPolicy(), GrpcClientSettingsManager.DEFAULT_CONSUMER_SETTINGS.getBackoffPolicy()); + + subscriptionGroupConfig.setRetryMaxTimes(3); + subscriptionGroupConfig.getGroupRetryPolicy().setType(GroupRetryPolicyType.CUSTOMIZED); + subscriptionGroupConfig.getGroupRetryPolicy().setCustomizedRetryPolicy(new CustomizedRetryPolicy(new long[]{1000})); + settings = this.grpcClientSettingsManager.getClientSettings(context); + assertEquals(RetryPolicy.newBuilder() + .setMaxAttempts(3) + .setCustomizedBackoff(CustomizedBackoff.newBuilder() + .addNext(Durations.fromSeconds(1)) + .build()) + .build(), settings.getBackoffPolicy()); + + subscriptionGroupConfig.setRetryMaxTimes(10); + subscriptionGroupConfig.getGroupRetryPolicy().setType(GroupRetryPolicyType.EXPONENTIAL); + subscriptionGroupConfig.getGroupRetryPolicy().setExponentialRetryPolicy(new ExponentialRetryPolicy(1000, 2000, 3)); + settings = this.grpcClientSettingsManager.getClientSettings(context); + assertEquals(RetryPolicy.newBuilder() + .setMaxAttempts(10) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setMax(Durations.fromSeconds(2)) + .setInitial(Durations.fromSeconds(1)) + .setMultiplier(3) + .build()) + .build(), settings.getBackoffPolicy()); + + Settings settings1 = this.grpcClientSettingsManager.removeAndGetClientSettings(context); + assertEquals(settings, settings1); + + assertNull(this.grpcClientSettingsManager.getClientSettings(context)); + assertNull(this.grpcClientSettingsManager.removeAndGetClientSettings(context)); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java new file mode 100644 index 0000000000..a6d6d60f14 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java @@ -0,0 +1,150 @@ +/* + * 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.service.relay; + +import io.netty.channel.Channel; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ProxyChannelTest { + + @Mock + private ProxyRelayService proxyRelayService; + + protected abstract static class MockProxyChannel extends ProxyChannel { + + protected MockProxyChannel(ProxyRelayService proxyRelayService, Channel parent, + String remoteAddress, String localAddress) { + super(proxyRelayService, parent, remoteAddress, localAddress); + } + + @Override public boolean isOpen() { + return false; + } + + @Override public boolean isActive() { + return false; + } + } + + @Test + public void testWriteAndFlush() throws Exception { + ArgumentCaptor consumeMessageDirectlyArgumentCaptor = + ArgumentCaptor.forClass(ConsumeMessageDirectlyResultRequestHeader.class); + when(this.proxyRelayService.processConsumeMessageDirectly(any(), any(), consumeMessageDirectlyArgumentCaptor.capture())) + .thenReturn(new CompletableFuture<>()); + + ArgumentCaptor getConsumerRunningInfoArgumentCaptor = + ArgumentCaptor.forClass(GetConsumerRunningInfoRequestHeader.class); + when(this.proxyRelayService.processGetConsumerRunningInfo(any(), any(), getConsumerRunningInfoArgumentCaptor.capture())) + .thenReturn(new CompletableFuture<>()); + + CheckTransactionStateRequestHeader checkTransactionStateRequestHeader = new CheckTransactionStateRequestHeader(); + checkTransactionStateRequestHeader.setBrokerName("broker"); + checkTransactionStateRequestHeader.setTransactionId(MessageClientIDSetter.createUniqID()); + RemotingCommand checkTransactionRequest = RemotingCommand.createRequestCommand(RequestCode.CHECK_TRANSACTION_STATE, checkTransactionStateRequestHeader); + MessageExt transactionMessageExt = new MessageExt(); + transactionMessageExt.setTopic("topic"); + transactionMessageExt.setTags("tags"); + transactionMessageExt.setBornHost(RemotingUtil.string2SocketAddress("127.0.0.2:8888")); + transactionMessageExt.setStoreHost(RemotingUtil.string2SocketAddress("127.0.0.1:10911")); + transactionMessageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + transactionMessageExt.setMsgId(MessageClientIDSetter.createUniqID()); + checkTransactionRequest.setBody(MessageDecoder.encode(transactionMessageExt, false)); + + GetConsumerRunningInfoRequestHeader consumerRunningInfoRequestHeader = new GetConsumerRunningInfoRequestHeader(); + consumerRunningInfoRequestHeader.setConsumerGroup("group"); + consumerRunningInfoRequestHeader.setClientId("clientId"); + RemotingCommand consumerRunningInfoRequest = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_RUNNING_INFO, consumerRunningInfoRequestHeader); + + ConsumeMessageDirectlyResultRequestHeader consumeMessageDirectlyResultRequestHeader = new ConsumeMessageDirectlyResultRequestHeader(); + consumeMessageDirectlyResultRequestHeader.setConsumerGroup("group"); + consumeMessageDirectlyResultRequestHeader.setClientId("clientId"); + MessageExt consumeMessageDirectlyMessageExt = new MessageExt(); + consumeMessageDirectlyMessageExt.setTopic("topic"); + consumeMessageDirectlyMessageExt.setTags("tags"); + consumeMessageDirectlyMessageExt.setBornHost(RemotingUtil.string2SocketAddress("127.0.0.2:8888")); + consumeMessageDirectlyMessageExt.setStoreHost(RemotingUtil.string2SocketAddress("127.0.0.1:10911")); + consumeMessageDirectlyMessageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + consumeMessageDirectlyMessageExt.setMsgId(MessageClientIDSetter.createUniqID()); + RemotingCommand consumeMessageDirectlyResult = RemotingCommand.createRequestCommand(RequestCode.CONSUME_MESSAGE_DIRECTLY, consumeMessageDirectlyResultRequestHeader); + consumeMessageDirectlyResult.setBody(MessageDecoder.encode(consumeMessageDirectlyMessageExt, false)); + + MockProxyChannel channel = new MockProxyChannel(this.proxyRelayService, null, "127.0.0.2:8888", "127.0.0.1:10911") { + @Override + protected CompletableFuture processOtherMessage(Object msg) { + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, + MessageExt messageExt, TransactionId transactionId) { + assertEquals(checkTransactionStateRequestHeader, header); + assertArrayEquals(transactionMessageExt.getBody(), messageExt.getBody()); + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processGetConsumerRunningInfo(RemotingCommand command, + GetConsumerRunningInfoRequestHeader header, + CompletableFuture> responseFuture) { + assertEquals(consumerRunningInfoRequestHeader, getConsumerRunningInfoArgumentCaptor.getValue()); + assertEquals(consumerRunningInfoRequestHeader, header); + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture processConsumeMessageDirectly(RemotingCommand command, + ConsumeMessageDirectlyResultRequestHeader header, MessageExt messageExt, + CompletableFuture> responseFuture) { + assertEquals(consumeMessageDirectlyResultRequestHeader, consumeMessageDirectlyArgumentCaptor.getValue()); + assertEquals(consumeMessageDirectlyResultRequestHeader, header); + assertArrayEquals(consumeMessageDirectlyMessageExt.getBody(), messageExt.getBody()); + return CompletableFuture.completedFuture(null); + } + }; + + assertTrue(channel.writeAndFlush(checkTransactionRequest).isSuccess()); + assertTrue(channel.writeAndFlush(consumerRunningInfoRequest).isSuccess()); + assertTrue(channel.writeAndFlush(consumeMessageDirectlyResult).isSuccess()); + } +} \ No newline at end of file From 8bb6af15e3889104dd0da5dab50d8a5f4a622a7c Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 24 May 2022 16:04:29 +0800 Subject: [PATCH 204/338] [ISSUE #3949] Use MessageExt property to get TopicMessageType --- .../proxy/common/ContextVariable.java | 1 - .../proxy/common/ProxyExceptionCode.java | 2 +- .../grpc/v2/common/GrpcProxyException.java | 1 + .../grpc/v2/producer/SendMessageActivity.java | 5 +---- .../proxy/processor/AbstractProcessor.java | 19 +++++++++++++++++++ .../proxy/processor/ProducerProcessor.java | 6 +++--- .../DefaultTopicMessageTypeValidator.java | 2 +- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index f77ad376f4..fcc6bb02ff 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -20,5 +20,4 @@ package org.apache.rocketmq.proxy.common; public class ContextVariable { public final static String REMOTE_ADDRESS = "remote-address"; public final static String LOCAL_ADDRESS = "local-address"; - public final static String MESSAGE_TYPE = "message-type"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 50a5ce1353..662df1b900 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -23,5 +23,5 @@ public enum ProxyExceptionCode { INVALID_RECEIPT_HANDLE, ILLEGAL_MESSAGE, INTERNAL_SERVER_ERROR, - TOPIC_MESSAGE_TYPE_NOT_MATCH, + MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index ed1eaf1197..f89639dc58 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -36,6 +36,7 @@ public class GrpcProxyException extends RuntimeException { CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); CODE_MAPPING.put(ProxyExceptionCode.ILLEGAL_MESSAGE, Code.ILLEGAL_MESSAGE); CODE_MAPPING.put(ProxyExceptionCode.INTERNAL_SERVER_ERROR, Code.INTERNAL_SERVER_ERROR); + CODE_MAPPING.put(ProxyExceptionCode.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, Code.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE); } public GrpcProxyException(Code code, String message) { 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 59bbb0ea0b..ca215e6777 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 @@ -45,10 +45,7 @@ import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.common.ContextVariable; 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.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; @@ -85,7 +82,7 @@ public class SendMessageActivity extends AbstractMessingActivity { List messageList = request.getMessagesList(); Resource topic = messageList.get(0).getTopic(); future = this.messagingProcessor.sendMessage( - context.withVal(ContextVariable.MESSAGE_TYPE, topicMessageType.getValue()), + context, new SendMessageQueueSelector(request), GrpcConverter.wrapResourceWithNamespace(topic), buildMessage(context, request.getMessagesList(), topic) 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 bf47d2d116..6a97754b01 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 @@ -16,7 +16,10 @@ */ package org.apache.rocketmq.proxy.processor; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.ServiceManager; @@ -37,4 +40,20 @@ public abstract class AbstractProcessor { throw new ProxyException(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, "receipt handle is expired"); } } + + protected TopicMessageType parseFromMessageExt(MessageExt messageExt) { + String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + String isTransValue = "true"; + if (isTransValue.equals(isTrans)) { + return TopicMessageType.TRANSACTION; + } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null + || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + return TopicMessageType.DELAY; + } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { + return TopicMessageType.FIFO; + } else { + return TopicMessageType.NORMAL; + } + } } 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 b93187380a..2007fa53cd 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 @@ -33,7 +33,6 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; @@ -62,11 +61,12 @@ public class ProducerProcessor extends AbstractProcessor { String producerGroup, List messageExtList, long timeoutMillis) { CompletableFuture> future = new CompletableFuture<>(); try { - String topic = messageExtList.get(0).getTopic(); + MessageExt messageExt0 = messageExtList.get(0); + String topic = messageExt0.getTopic(); if (ConfigurationManager.getProxyConfig().isEnableTopicMessageTypeCheck()) { if (topicMessageTypeValidator != null) { TopicMessageType topicMessageType = serviceManager.getMetadataService().getTopicMessageType(topic); - TopicMessageType messageType = TopicMessageType.valueOf(ctx.getVal(ContextVariable.MESSAGE_TYPE)); + TopicMessageType messageType = parseFromMessageExt(messageExt0); topicMessageTypeValidator.validate(topicMessageType, messageType); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java index a0718c5ced..eaa4144c5f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java @@ -25,7 +25,7 @@ public class DefaultTopicMessageTypeValidator implements TopicMessageTypeValidat public void validate(TopicMessageType topicMessageType, TopicMessageType messageType) { if (messageType.equals(TopicMessageType.UNSPECIFIED) || !messageType.equals(topicMessageType)) { - throw new ProxyException(ProxyExceptionCode.TOPIC_MESSAGE_TYPE_NOT_MATCH, messageType.name() + " " + topicMessageType.name()); + throw new ProxyException(ProxyExceptionCode.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, messageType.name() + " " + topicMessageType.name()); } } } From 8199c6d7b932cca1e4e75296c5d47b4d8edcfbe0 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 24 May 2022 15:49:01 +0800 Subject: [PATCH 205/338] [ISSUE #3949] Complete processConsumeMessageDirectly and refector --- .../service/relay/LocalProxyRelayService.java | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index c39cc3f262..babac00397 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -26,7 +26,6 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; -import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -44,19 +43,21 @@ public class LocalProxyRelayService implements ProxyRelayService { ProxyContext context, RemotingCommand command, GetConsumerRunningInfoRequestHeader header) { CompletableFuture> future = new CompletableFuture<>(); future.thenAccept(proxyOutResult -> { - if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { - ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); - RemotingServer remotingServer = this.brokerController.getRemotingServer(); - if (remotingServer instanceof NettyRemotingAbstract) { - NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; - RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "from gRPC client"); - remotingCommand.setOpaque(command.getOpaque()); + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(null); + remotingCommand.setOpaque(command.getOpaque()); + remotingCommand.setCode(proxyOutResult.getCode()); + remotingCommand.setRemark(proxyOutResult.getRemark()); + if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { + ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); runningInfo.setJstack(consumerRunningInfo.getJstack()); remotingCommand.setBody(runningInfo.encode()); - SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); - nettyRemotingAbstract.processResponseCommand(new SimpleChannelHandlerContext(simpleChannel), remotingCommand); } + SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + nettyRemotingAbstract.processResponseCommand(simpleChannel.getChannelHandlerContext(), remotingCommand); } }); return future; @@ -66,6 +67,23 @@ public class LocalProxyRelayService implements ProxyRelayService { public CompletableFuture> processConsumeMessageDirectly( ProxyContext context, RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { - return null; + CompletableFuture> future = new CompletableFuture<>(); + future.thenAccept(proxyOutResult -> { + RemotingServer remotingServer = this.brokerController.getRemotingServer(); + if (remotingServer instanceof NettyRemotingAbstract) { + NettyRemotingAbstract nettyRemotingAbstract = (NettyRemotingAbstract) remotingServer; + RemotingCommand remotingCommand = RemotingCommand.createResponseCommand(null); + remotingCommand.setOpaque(command.getOpaque()); + remotingCommand.setCode(proxyOutResult.getCode()); + remotingCommand.setRemark(proxyOutResult.getRemark()); + if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { + ConsumeMessageDirectlyResult consumeMessageDirectlyResult = proxyOutResult.getResult(); + remotingCommand.setBody(consumeMessageDirectlyResult.encode()); + } + SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + nettyRemotingAbstract.processResponseCommand(simpleChannel.getChannelHandlerContext(), remotingCommand); + } + }); + return future; } } From 908f977e7e0f0e442d2f9be21114b651b5463de5 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 24 May 2022 16:23:48 +0800 Subject: [PATCH 206/338] [ISSUE #3949] Add unit test for ProducerProcessor --- .../proxy/processor/ProducerProcessor.java | 10 +++-- .../proxy/processor/BaseProcessorTest.java | 4 ++ .../processor/ProducerProcessorTest.java | 42 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) 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 2007fa53cd..d9666559f2 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 @@ -29,6 +29,7 @@ import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; @@ -65,9 +66,12 @@ public class ProducerProcessor extends AbstractProcessor { String topic = messageExt0.getTopic(); if (ConfigurationManager.getProxyConfig().isEnableTopicMessageTypeCheck()) { if (topicMessageTypeValidator != null) { - TopicMessageType topicMessageType = serviceManager.getMetadataService().getTopicMessageType(topic); - TopicMessageType messageType = parseFromMessageExt(messageExt0); - topicMessageTypeValidator.validate(topicMessageType, messageType); + // Do not check retry or dlq topic + if (!NamespaceUtil.isRetryTopic(topic) && !NamespaceUtil.isDLQTopic(topic)) { + TopicMessageType topicMessageType = serviceManager.getMetadataService().getTopicMessageType(topic); + TopicMessageType messageType = parseFromMessageExt(messageExt0); + topicMessageTypeValidator.validate(topicMessageType, messageType); + } } } SelectableMessageQueue messageQueue = queueSelector.select(ctx, 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 31954705b7..f67d861158 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 @@ -31,6 +31,7 @@ import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.message.MessageService; +import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; @@ -63,6 +64,8 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { @Mock protected ProxyRelayService proxyRelayService; @Mock + protected MetadataService metadataService; + @Mock protected ProducerProcessor producerProcessor; @Mock protected ConsumerProcessor consumerProcessor; @@ -79,6 +82,7 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { when(serviceManager.getConsumerManager()).thenReturn(consumerManager); when(serviceManager.getTransactionService()).thenReturn(transactionService); when(serviceManager.getProxyRelayService()).thenReturn(proxyRelayService); + when(serviceManager.getMetadataService()).thenReturn(metadataService); } protected static ProxyContext createContext() { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index eac0abe553..7208c6da83 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -25,6 +25,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; @@ -46,6 +47,7 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -65,6 +67,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { @Test public void testSendMessage() throws Throwable { + when(metadataService.getTopicMessageType(eq(TOPIC))).thenReturn(TopicMessageType.NORMAL); String txId = MessageClientIDSetter.createUniqID(); String msgId = MessageClientIDSetter.createUniqID(); @@ -76,6 +79,45 @@ public class ProducerProcessorTest extends BaseProcessorTest { when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); + List messageExtList = new ArrayList<>(); + MessageExt messageExt = createMessageExt(TOPIC, "tag", 0, 0); + messageExt.setSysFlag(MessageSysFlag.TRANSACTION_PREPARED_TYPE); + messageExtList.add(messageExt); + SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + when(messageQueue.getBrokerName()).thenReturn("mockBroker"); + + List sendResultList = this.producerProcessor.sendMessage( + createContext(), + (ctx, messageQueueView) -> messageQueue, + PRODUCER_GROUP, + messageExtList, + 3000 + ).get(); + + assertNotNull(sendResultList); + TransactionId transactionId = TransactionId.decode(sendResultList.get(0).getTransactionId()); + assertNotNull(transactionId); + assertEquals(txId, transactionId.getBrokerTransactionId()); + assertEquals("mockBroker", transactionId.getBrokerName()); + + SendMessageRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); + assertEquals(PRODUCER_GROUP, requestHeader.getProducerGroup()); + assertEquals(TOPIC, requestHeader.getTopic()); + } + + @Test + public void testSendRetryMessage() throws Throwable { + String txId = MessageClientIDSetter.createUniqID(); + String msgId = MessageClientIDSetter.createUniqID(); + + SendResult sendResult = new SendResult(); + sendResult.setSendStatus(SendStatus.SEND_OK); + sendResult.setTransactionId(txId); + sendResult.setMsgId(msgId); + ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); + when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) + .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); + List messageExtList = new ArrayList<>(); MessageExt messageExt = createMessageExt(MixAll.getRetryTopic(CONSUMER_GROUP), "tag", 0, 0); messageExt.setSysFlag(MessageSysFlag.TRANSACTION_PREPARED_TYPE); From 7647caf90d2b98e442e465885e424e44fb8e54f3 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 24 May 2022 17:45:13 +0800 Subject: [PATCH 207/338] [ISSUE #3949] merge GrpcContextConstants into ContextVariable --- .../proxy/common/ContextVariable.java | 2 ++ .../grpc/v2/AbstractMessingActivity.java | 5 ++-- .../proxy/grpc/v2/GrpcContextConstants.java | 23 ------------------- .../proxy/grpc/v2/client/ClientActivity.java | 12 +++++----- .../v2/common/GrpcClientSettingsManager.java | 6 ++--- .../processor/DefaultMessagingProcessor.java | 10 ++++---- .../proxy/service/ClusterServiceManager.java | 8 +++---- .../common/GrpcClientSettingsManagerTest.java | 4 ++-- 8 files changed, 25 insertions(+), 45 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index fcc6bb02ff..27cc04cc2a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -20,4 +20,6 @@ package org.apache.rocketmq.proxy.common; public class ContextVariable { public final static String REMOTE_ADDRESS = "remote-address"; public final static String LOCAL_ADDRESS = "local-address"; + public static final String CLIENT_ID = "client-id"; + public static final String LANGUAGE = "language"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 24ef2f40f1..7ca356df12 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.grpc.v2; import io.grpc.Context; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; @@ -36,7 +37,7 @@ public abstract class AbstractMessingActivity { protected ProxyContext createContext(Context ctx) { return ProxyContext.create() - .withVal(GrpcContextConstants.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) - .withVal(GrpcContextConstants.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); + .withVal(ContextVariable.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) + .withVal(ContextVariable.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java deleted file mode 100644 index 061766c0eb..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcContextConstants.java +++ /dev/null @@ -1,23 +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.proxy.grpc.v2; - -public class GrpcContextConstants { - - public static final String CLIENT_ID = "client_id"; - public static final String LANGUAGE = "language"; -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 5b149288cd..341f3fef8f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -54,9 +54,9 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; -import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; @@ -92,8 +92,8 @@ public class ClientActivity extends AbstractMessingActivity { try { ProxyContext context = createContext(ctx); - String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); - LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); + String clientId = context.getVal(ContextVariable.CLIENT_ID); + LanguageCode languageCode = context.getVal(ContextVariable.LANGUAGE); Settings clientSettings = grpcClientSettingsManager.getClientSettings(context); switch (clientSettings.getClientType()) { @@ -151,8 +151,8 @@ public class ClientActivity extends AbstractMessingActivity { try { ProxyContext context = createContext(ctx); - String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); - LanguageCode languageCode = context.getVal(GrpcContextConstants.LANGUAGE); + String clientId = context.getVal(ContextVariable.CLIENT_ID); + LanguageCode languageCode = context.getVal(ContextVariable.LANGUAGE); Settings clientSettings = grpcClientSettingsManager.removeAndGetClientSettings(context); switch (clientSettings.getClientType()) { @@ -229,7 +229,7 @@ public class ClientActivity extends AbstractMessingActivity { protected TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, StreamObserver responseObserver) { ProxyContext context = createContext(ctx); - String clientId = context.getVal(GrpcContextConstants.CLIENT_ID); + String clientId = context.getVal(ContextVariable.CLIENT_ID); grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); Settings settings = grpcClientSettingsManager.getClientSettings(context); if (settings.hasPublishing()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index f2cd66a43e..d041039a3e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -35,9 +35,9 @@ import org.apache.rocketmq.common.subscription.ExponentialRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class GrpcClientSettingsManager { @@ -73,7 +73,7 @@ public class GrpcClientSettingsManager { } public Settings getClientSettings(ProxyContext ctx) { - String clientId = ctx.getVal(GrpcContextConstants.CLIENT_ID); + String clientId = ctx.getVal(ContextVariable.CLIENT_ID); Settings settings = CLIENT_SETTINGS_MAP.get(clientId); if (settings == null) { return null; @@ -149,7 +149,7 @@ public class GrpcClientSettingsManager { } public Settings removeAndGetClientSettings(ProxyContext ctx) { - String clientId = ctx.getVal(GrpcContextConstants.CLIENT_ID); + String clientId = ctx.getVal(ContextVariable.CLIENT_ID); Settings settings = CLIENT_SETTINGS_MAP.remove(clientId); if (settings == null) { return null; 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 44816f1adc..b33c4f2042 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 @@ -54,11 +54,11 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class DefaultMessagingProcessor extends AbstractStartAndShutdown implements MessagingProcessor { - private final ServiceManager serviceManager; - private final ProducerProcessor producerProcessor; - private final ConsumerProcessor consumerProcessor; - private final TransactionProcessor transactionProcessor; - private final ClientProcessor clientProcessor; + protected final ServiceManager serviceManager; + protected final ProducerProcessor producerProcessor; + protected final ConsumerProcessor consumerProcessor; + protected final TransactionProcessor transactionProcessor; + protected final ClientProcessor clientProcessor; protected final ThreadPoolExecutor producerProcessorExecutor; protected final ThreadPoolExecutor consumerProcessorExecutor; 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 ce529b16e1..cd37acaf09 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 @@ -58,10 +58,10 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S private final ProxyRelayService proxyRelayService; private final ClusterMetadataService metadataService; - private final ScheduledExecutorService scheduledExecutorService; - private final MQClientAPIFactory messagingClientAPIFactory; - private final MQClientAPIFactory operationClientAPIFactory; - private final MQClientAPIFactory transactionClientAPIFactory; + protected final ScheduledExecutorService scheduledExecutorService; + protected final MQClientAPIFactory messagingClientAPIFactory; + protected final MQClientAPIFactory operationClientAPIFactory; + protected final MQClientAPIFactory transactionClientAPIFactory; public ClusterServiceManager(RPCHook rpcHook) { this.scheduledExecutorService = Executors.newScheduledThreadPool(3); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java index 056eeb4018..bf89caab64 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java @@ -28,9 +28,9 @@ import org.apache.rocketmq.common.subscription.CustomizedRetryPolicy; import org.apache.rocketmq.common.subscription.ExponentialRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; -import org.apache.rocketmq.proxy.grpc.v2.GrpcContextConstants; import org.junit.Before; import org.junit.Test; @@ -60,7 +60,7 @@ public class GrpcClientSettingsManagerTest extends BaseActivityTest { .build()) .build()); - ProxyContext context = ProxyContext.create().withVal(GrpcContextConstants.CLIENT_ID, CLIENT_ID); + ProxyContext context = ProxyContext.create().withVal(ContextVariable.CLIENT_ID, CLIENT_ID); Settings settings = this.grpcClientSettingsManager.getClientSettings(context); assertEquals(settings.getBackoffPolicy(), GrpcClientSettingsManager.DEFAULT_CONSUMER_SETTINGS.getBackoffPolicy()); From d44949f90b75687d819d9b2c2b39e259f6138898 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 25 May 2022 11:31:29 +0800 Subject: [PATCH 208/338] [ISSUE #3949] add test cases --- .../service/mqclient/MQClientAPIExt.java | 20 +- .../service/mqclient/MQClientAPIExtTest.java | 345 ++++++++++++++++++ 2 files changed, 356 insertions(+), 9 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index c45db7fa37..011500f8a2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -322,15 +322,17 @@ public class MQClientAPIExt extends MQClientAPIImpl { new PullCallback() { @Override public void onSuccess(PullResult pullResult) { - PullResultExt pullResultExt = (PullResultExt) pullResult; - if (PullStatus.FOUND.equals(pullResult.getPullStatus())) { - List messageExtList = MessageDecoder.decodesBatch( - ByteBuffer.wrap(pullResultExt.getMessageBinary()), - true, - false, - true - ); - pullResult.setMsgFoundList(messageExtList); + if (pullResult instanceof PullResultExt) { + PullResultExt pullResultExt = (PullResultExt) pullResult; + if (PullStatus.FOUND.equals(pullResult.getPullStatus())) { + List messageExtList = MessageDecoder.decodesBatch( + ByteBuffer.wrap(pullResultExt.getMessageBinary()), + true, + false, + true + ); + pullResult.setMsgFoundList(messageExtList); + } } future.complete(pullResult); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java new file mode 100644 index 0000000000..b78502e2c1 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java @@ -0,0 +1,345 @@ +/* + * 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.service.mqclient; + +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import org.apache.rocketmq.client.ClientConfig; +import org.apache.rocketmq.client.consumer.AckCallback; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.PopCallback; +import org.apache.rocketmq.client.consumer.PopResult; +import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.client.consumer.PullCallback; +import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.consumer.PullStatus; +import org.apache.rocketmq.client.impl.CommunicationMode; +import org.apache.rocketmq.client.impl.MQClientAPIImpl; +import org.apache.rocketmq.client.impl.consumer.PullResultExt; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; +import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetResponseHeader; +import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; +import org.apache.rocketmq.remoting.InvokeCallback; +import org.apache.rocketmq.remoting.RemotingClient; +import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.netty.NettyClientConfig; +import org.apache.rocketmq.remoting.netty.ResponseFuture; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; + +@RunWith(MockitoJUnitRunner.class) +public class MQClientAPIExtTest { + + private static final String BROKER_ADDR = "127.0.0.1:10911"; + private static final String BROKER_NAME = "brokerName"; + private static final long TIMEOUT = 3000; + private static final String CONSUMER_GROUP = "group"; + private static final String TOPIC = "topic"; + + @Spy + private final MQClientAPIExt mqClientAPI = new MQClientAPIExt(new ClientConfig(), new NettyClientConfig(), new DoNothingClientRemotingProcessor(null), null); + @Mock + private RemotingClient remotingClient; + + @Before + public void init() throws Exception { + Field field = MQClientAPIImpl.class.getDeclaredField("remotingClient"); + field.setAccessible(true); + field.set(mqClientAPI, remotingClient); + } + + @Test + public void testSendHeartbeatAsync() throws Exception { + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + responseFuture.putResponse(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + assertNotNull(mqClientAPI.sendHeartbeatAsync(BROKER_ADDR, new HeartbeatData(), TIMEOUT).get()); + } + + @Test + public void testSendMessageAsync() throws Exception { + AtomicReference msgIdRef = new AtomicReference<>(); + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class); + SendMessageResponseHeader sendMessageResponseHeader = (SendMessageResponseHeader) response.readCustomHeader(); + sendMessageResponseHeader.setMsgId(msgIdRef.get()); + sendMessageResponseHeader.setQueueId(0); + sendMessageResponseHeader.setQueueOffset(1L); + response.setCode(ResponseCode.SUCCESS); + response.makeCustomHeaderToNet(); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + MessageExt messageExt = createMessage(); + msgIdRef.set(MessageClientIDSetter.getUniqID(messageExt)); + + SendResult sendResult = mqClientAPI.sendMessageAsync(BROKER_ADDR, BROKER_NAME, messageExt, new SendMessageRequestHeader(), TIMEOUT) + .get(); + assertNotNull(sendResult); + assertEquals(msgIdRef.get(), sendResult.getMsgId()); + assertEquals(SendStatus.SEND_OK, sendResult.getSendStatus()); + } + + @Test + public void testSendMessageListAsync() throws Exception { + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class); + SendMessageResponseHeader sendMessageResponseHeader = (SendMessageResponseHeader) response.readCustomHeader(); + sendMessageResponseHeader.setMsgId(""); + sendMessageResponseHeader.setQueueId(0); + sendMessageResponseHeader.setQueueOffset(1L); + response.setCode(ResponseCode.SUCCESS); + response.makeCustomHeaderToNet(); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + List messageExtList = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 3; i++) { + MessageExt messageExt = createMessage(); + sb.append(sb.length() == 0 ? "" : ",").append(MessageClientIDSetter.getUniqID(messageExt)); + messageExtList.add(messageExt); + } + + SendResult sendResult = mqClientAPI.sendMessageAsync(BROKER_ADDR, BROKER_NAME, messageExtList, new SendMessageRequestHeader(), TIMEOUT) + .get(); + assertNotNull(sendResult); + assertEquals(sb.toString(), sendResult.getMsgId()); + assertEquals(SendStatus.SEND_OK, sendResult.getSendStatus()); + } + + @Test + public void testSendMessageBackAsync() throws Exception { + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + responseFuture.putResponse(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "")); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + RemotingCommand remotingCommand = mqClientAPI.sendMessageBackAsync(BROKER_ADDR, new ConsumerSendMsgBackRequestHeader(), TIMEOUT) + .get(); + assertNotNull(remotingCommand); + assertEquals(ResponseCode.SUCCESS, remotingCommand.getCode()); + } + + @Test + public void testPopMessageAsync() throws Exception { + PopResult popResult = new PopResult(PopStatus.POLLING_NOT_FOUND, null); + doAnswer((Answer) mock -> { + PopCallback popCallback = mock.getArgument(4); + popCallback.onSuccess(popResult); + return null; + }).when(mqClientAPI).popMessageAsync(anyString(), anyString(), any(), anyLong(), any()); + + assertSame(popResult, mqClientAPI.popMessageAsync(BROKER_ADDR, BROKER_NAME, new PopMessageRequestHeader(), TIMEOUT).get()); + } + + @Test + public void testAckMessageAsync() throws Exception { + AckResult ackResult = new AckResult(); + doAnswer((Answer) mock -> { + AckCallback ackCallback = mock.getArgument(2); + ackCallback.onSuccess(ackResult); + return null; + }).when(mqClientAPI).ackMessageAsync(anyString(), anyLong(), any(AckCallback.class), any()); + + assertSame(ackResult, mqClientAPI.ackMessageAsync(BROKER_ADDR, new AckMessageRequestHeader(), TIMEOUT).get()); + } + + @Test + public void testChangeInvisibleTimeAsync() throws Exception { + AckResult ackResult = new AckResult(); + doAnswer((Answer) mock -> { + AckCallback ackCallback = mock.getArgument(4); + ackCallback.onSuccess(ackResult); + return null; + }).when(mqClientAPI).changeInvisibleTimeAsync(anyString(), anyString(), any(), anyLong(), any(AckCallback.class)); + + assertSame(ackResult, mqClientAPI.changeInvisibleTimeAsync(BROKER_ADDR, BROKER_NAME, new ChangeInvisibleTimeRequestHeader(), TIMEOUT).get()); + } + + @Test + public void testPullMessageAsync() throws Exception { + MessageExt msg1 = createMessage(); + byte[] msg1Byte = MessageDecoder.encode(msg1, false); + MessageExt msg2 = createMessage(); + byte[] msg2Byte = MessageDecoder.encode(msg2, false); + + ByteBuffer byteBuffer = ByteBuffer.allocate(msg1Byte.length + msg2Byte.length); + byteBuffer.put(msg1Byte); + byteBuffer.put(msg2Byte); + + PullResultExt pullResultExt = new PullResultExt(PullStatus.FOUND, 0, 0, 1, null, 0, + byteBuffer.array()); + doAnswer((Answer) mock -> { + PullCallback pullCallback = mock.getArgument(4); + pullCallback.onSuccess(pullResultExt); + return null; + }).when(mqClientAPI).pullMessage(anyString(), any(), anyLong(), any(CommunicationMode.class), any(PullCallback.class)); + + PullResult pullResult = mqClientAPI.pullMessageAsync(BROKER_ADDR, new PullMessageRequestHeader(), TIMEOUT).get(); + assertNotNull(pullResult); + assertEquals(2, pullResult.getMsgFoundList().size()); + + Set msgIdSet = pullResult.getMsgFoundList().stream().map(MessageClientIDSetter::getUniqID).collect(Collectors.toSet()); + assertTrue(msgIdSet.contains(MessageClientIDSetter.getUniqID(msg1))); + assertTrue(msgIdSet.contains(MessageClientIDSetter.getUniqID(msg2))); + } + + @Test + public void testGetConsumerListByGroupAsync() throws Exception { + List clientIds = Lists.newArrayList("clientIds"); + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(GetConsumerListByGroupResponseHeader.class); + response.setCode(ResponseCode.SUCCESS); + response.makeCustomHeaderToNet(); + GetConsumerListByGroupResponseBody body = new GetConsumerListByGroupResponseBody(); + body.setConsumerIdList(clientIds); + response.setBody(body.encode()); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + List res = mqClientAPI.getConsumerListByGroupAsync(BROKER_ADDR, new GetConsumerListByGroupRequestHeader(), TIMEOUT).get(); + assertEquals(clientIds, res); + } + + @Test + public void testGetEmptyConsumerListByGroupAsync() throws Exception { + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(GetConsumerListByGroupRequestHeader.class); + response.setCode(ResponseCode.SYSTEM_ERROR); + response.makeCustomHeaderToNet(); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + List res = mqClientAPI.getConsumerListByGroupAsync(BROKER_ADDR, new GetConsumerListByGroupRequestHeader(), TIMEOUT).get(); + assertTrue(res.isEmpty()); + } + + @Test + public void testGetMaxOffsetAsync() throws Exception { + long offset = ThreadLocalRandom.current().nextLong(); + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(GetMaxOffsetResponseHeader.class); + GetMaxOffsetResponseHeader responseHeader = (GetMaxOffsetResponseHeader) response.readCustomHeader(); + responseHeader.setOffset(offset); + response.setCode(ResponseCode.SUCCESS); + response.makeCustomHeaderToNet(); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + assertEquals(offset, mqClientAPI.getMaxOffsetAsync(BROKER_ADDR, TOPIC, 0, TIMEOUT).get().longValue()); + } + + + @Test + public void testSearchOffsetAsync() throws Exception { + long offset = ThreadLocalRandom.current().nextLong(); + doAnswer((Answer) mock -> { + InvokeCallback invokeCallback = mock.getArgument(3); + ResponseFuture responseFuture = new ResponseFuture(null, 0, 3000, invokeCallback, null); + RemotingCommand response = RemotingCommand.createResponseCommand(SearchOffsetResponseHeader.class); + SearchOffsetResponseHeader responseHeader = (SearchOffsetResponseHeader) response.readCustomHeader(); + responseHeader.setOffset(offset); + response.setCode(ResponseCode.SUCCESS); + response.makeCustomHeaderToNet(); + responseFuture.putResponse(response); + invokeCallback.operationComplete(responseFuture); + return null; + }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); + + assertEquals(offset, mqClientAPI.searchOffsetAsync(BROKER_ADDR, TOPIC, 0, System.currentTimeMillis(), TIMEOUT).get().longValue()); + } + + protected MessageExt createMessage() { + MessageExt messageExt = new MessageExt(); + messageExt.setTopic("topic"); + messageExt.setBornHost(RemotingUtil.string2SocketAddress("127.0.0.2:8888")); + messageExt.setStoreHost(RemotingUtil.string2SocketAddress("127.0.0.1:10911")); + messageExt.setBody(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + MessageClientIDSetter.setUniqID(messageExt); + return messageExt; + } +} \ No newline at end of file From 989bd3ae53e8133bffc7ef7fab42f67fa8be8001 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 25 May 2022 11:38:16 +0800 Subject: [PATCH 209/338] [ISSUE #3949] fix test cases --- .../service/transaction/ClusterTransactionServiceTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java index 517838f42c..72fad8f13a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java @@ -126,12 +126,10 @@ public class ClusterTransactionServiceTest extends BaseServiceTest { assertEquals(Lists.newArrayList(BROKER_ADDR, BROKER_ADDR), brokerAddrArgumentCaptor.getAllValues()); List heartbeatDataList = heartbeatDataArgumentCaptor.getAllValues(); - assertEquals(2, heartbeatDataList.get(0).getProducerDataSet().size()); for (ProducerData producerData : heartbeatDataList.get(0).getProducerDataSet()) { groupSet.remove(producerData.getGroupName()); } - assertEquals(1, heartbeatDataList.get(1).getProducerDataSet().size()); for (ProducerData producerData : heartbeatDataList.get(1).getProducerDataSet()) { groupSet.remove(producerData.getGroupName()); } From f040e167d898d12baf8647a79f769e768380783f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 16:06:49 +0800 Subject: [PATCH 210/338] [ISSUE #3949] Support TopicMessageType --- .../rocketmq/common/TopicAttributes.java | 1 + .../apache/rocketmq/test/base/BaseConf.java | 24 ++++++++++++++-- .../test/base/IntegrationTestBase.java | 28 +++++++++++++++++++ .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 3 +- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java b/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java index 5ac1712985..8c7dd0ead3 100644 --- a/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java +++ b/common/src/main/java/org/apache/rocketmq/common/TopicAttributes.java @@ -42,5 +42,6 @@ public class TopicAttributes { static { ALL = new HashMap<>(); ALL.put(QUEUE_TYPE_ATTRIBUTE.getName(), QUEUE_TYPE_ATTRIBUTE); + ALL.put(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), TOPIC_MESSAGE_TYPE_ATTRIBUTE); } } diff --git a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java index 058ad91919..cd8d8aafd6 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java @@ -34,10 +34,11 @@ import org.apache.rocketmq.client.consumer.MQPushConsumer; import org.apache.rocketmq.client.producer.MQProducer; import org.apache.rocketmq.client.producer.TransactionListener; import org.apache.rocketmq.common.MQVersion; +import org.apache.rocketmq.common.attribute.CQType; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.namesrv.NamesrvController; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.apache.rocketmq.common.attribute.CQType; import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer; import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer; import org.apache.rocketmq.test.client.rmq.RMQNormalProducer; @@ -48,7 +49,6 @@ import org.apache.rocketmq.test.factory.ConsumerFactory; import org.apache.rocketmq.test.listener.AbstractListener; import org.apache.rocketmq.test.util.MQAdminTestUtils; import org.apache.rocketmq.test.util.MQRandomUtils; -import org.apache.rocketmq.test.util.RandomUtils; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import org.apache.rocketmq.tools.admin.MQAdminExt; import org.junit.Assert; @@ -141,21 +141,41 @@ public class BaseConf { return initTopicWithName(topic); } + public static String initTopic(TopicMessageType topicMessageType) { + String topic = MQRandomUtils.getRandomTopic(); + return initTopicWithName(topic, topicMessageType); + } + public static String initTopicOnSampleTopicBroker(String sampleTopic) { String topic = MQRandomUtils.getRandomTopic(); return initTopicOnSampleTopicBroker(topic, sampleTopic); } + public static String initTopicOnSampleTopicBroker(String sampleTopic, TopicMessageType topicMessageType) { + String topic = MQRandomUtils.getRandomTopic(); + return initTopicOnSampleTopicBroker(topic, sampleTopic, topicMessageType); + } + public static String initTopicWithName(String topicName) { IntegrationTestBase.initTopic(topicName, nsAddr, clusterName, CQType.SimpleCQ); return topicName; } + public static String initTopicWithName(String topicName, TopicMessageType topicMessageType) { + IntegrationTestBase.initTopic(topicName, nsAddr, clusterName, topicMessageType); + return topicName; + } + public static String initTopicOnSampleTopicBroker(String topicName, String sampleTopic) { IntegrationTestBase.initTopic(topicName, nsAddr, sampleTopic, CQType.SimpleCQ); return topicName; } + public static String initTopicOnSampleTopicBroker(String topicName, String sampleTopic, TopicMessageType topicMessageType) { + IntegrationTestBase.initTopic(topicName, nsAddr, sampleTopic, topicMessageType); + return topicName; + } + public static String initConsumerGroup() { String group = MQRandomUtils.getRandomConsumerGroup(); return initConsumerGroup(group); diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java index 398bd1943c..305275948b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java @@ -32,6 +32,7 @@ import org.apache.rocketmq.common.BrokerConfig; import org.apache.rocketmq.common.TopicAttributes; import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.common.attribute.CQType; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.namesrv.NamesrvConfig; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -168,6 +169,29 @@ public class IntegrationTestBase { return brokerController; } + public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, TopicMessageType topicMessageType) { + long startTime = System.currentTimeMillis(); + boolean createResult; + + while (true) { + Map attributes = new HashMap<>(); + attributes.put("+" + TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), topicMessageType.toString()); + createResult = MQAdminTestUtils.createTopic(nsAddr, clusterName, topic, queueNumbers, attributes); + if (createResult) { + break; + } else if (System.currentTimeMillis() - startTime > topicCreateTime) { + Truth.assertWithMessage(String.format("topic[%s] is created failed after:%d ms", topic, + System.currentTimeMillis() - startTime)).fail(); + break; + } else { + TestUtils.waitForMoment(500); + continue; + } + } + + return createResult; + } + public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, CQType cqType) { long startTime = System.currentTimeMillis(); boolean createResult; @@ -197,6 +221,10 @@ public class IntegrationTestBase { return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, cqType); } + public static boolean initTopic(String topic, String nsAddr, String clusterName, TopicMessageType topicMessageType) { + return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, topicMessageType); + } + public static void deleteFile(File file) { if (!file.exists()) { return; diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 38873fa9e8..28e50452ff 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -91,6 +91,7 @@ import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; @@ -209,7 +210,7 @@ public class GrpcBaseIT extends BaseConf { } public void testTransactionCheckThenCommit() { - String topic = initTopicOnSampleTopicBroker(broker1Name); + String topic = initTopicOnSampleTopicBroker(broker1Name, TopicMessageType.TRANSACTION); String group = MQRandomUtils.getRandomConsumerGroup(); AtomicReference telemetryCommandRef = new AtomicReference<>(null); From bd5fcf8f09b15e55133ba2867a6ea7134cd42279 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 16:09:25 +0800 Subject: [PATCH 211/338] [ISSUE #3949] Remove unused method in TransactionId --- .../service/transaction/TransactionId.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java index 3a22da078e..f031aa161e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java @@ -19,7 +19,6 @@ package org.apache.rocketmq.proxy.service.transaction; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.UtilAll; @@ -137,25 +136,6 @@ public class TransactionId { } } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TransactionId id = (TransactionId) o; - return commitLogOffset == id.commitLogOffset && tranStateTableOffset == id.tranStateTableOffset && - Objects.equals(brokerName, id.brokerName) && Objects.equals(brokerTransactionId, id.brokerTransactionId) && - Objects.equals(proxyTransactionId, id.proxyTransactionId); - } - - @Override - public int hashCode() { - return Objects.hash(brokerName, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); - } - public static TransactionIdBuilder builder() { return new TransactionIdBuilder(); } From ca6c531d62c05a429363f9affb134961b01ab303 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 17:22:28 +0800 Subject: [PATCH 212/338] [ISSUE #3949] Remove unused code in SendMessageActivity --- .../proxy/grpc/v2/producer/SendMessageActivity.java | 8 -------- 1 file changed, 8 deletions(-) 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 ca215e6777..d12d51953a 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 @@ -40,7 +40,6 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; @@ -53,18 +52,14 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; -import org.apache.rocketmq.proxy.processor.validator.DefaultTopicMessageTypeValidator; -import org.apache.rocketmq.proxy.processor.validator.TopicMessageTypeValidator; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; public class SendMessageActivity extends AbstractMessingActivity { - private final TopicMessageTypeValidator validator; public SendMessageActivity(MessagingProcessor messagingProcessor, GrpcClientSettingsManager grpcClientSettingsManager) { super(messagingProcessor, grpcClientSettingsManager); - this.validator = new DefaultTopicMessageTypeValidator(); } public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { @@ -76,9 +71,6 @@ public class SendMessageActivity extends AbstractMessingActivity { throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } - MessageType messageType = parseMessageType(request.getMessagesList()); - TopicMessageType topicMessageType = GrpcConverter.buildTopicMessageType(messageType); - List messageList = request.getMessagesList(); Resource topic = messageList.get(0).getTopic(); future = this.messagingProcessor.sendMessage( From 675b6c923214e64e980fab3229ccf7059a43afe0 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 17:22:53 +0800 Subject: [PATCH 213/338] [ISSUE #3949] Add LocalProxyRelayService unit test --- .../service/relay/LocalProxyRelayService.java | 4 +- .../relay/LocalProxyRelayServiceTest.java | 99 +++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index babac00397..3b68bb00f6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -52,9 +52,7 @@ public class LocalProxyRelayService implements ProxyRelayService { remotingCommand.setRemark(proxyOutResult.getRemark()); if (proxyOutResult.getCode() == ResponseCode.SUCCESS && proxyOutResult.getResult() != null) { ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); - ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); - runningInfo.setJstack(consumerRunningInfo.getJstack()); - remotingCommand.setBody(runningInfo.encode()); + remotingCommand.setBody(consumerRunningInfo.encode()); } SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); nettyRemotingAbstract.processResponseCommand(simpleChannel.getChannelHandlerContext(), remotingCommand); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java new file mode 100644 index 0000000000..52a71be530 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java @@ -0,0 +1,99 @@ +/* + * 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.service.relay; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.remoting.netty.NettyRemotingServer; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(MockitoJUnitRunner.class) +public class LocalProxyRelayServiceTest { + private LocalProxyRelayService localProxyRelayService; + @Mock + private BrokerController brokerControllerMock; + @Mock + private NettyRemotingServer nettyRemotingServerMock; + + @Before + public void setUp() { + localProxyRelayService = new LocalProxyRelayService(brokerControllerMock); + Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(nettyRemotingServerMock); + } + + @Test + public void testProcessGetConsumerRunningInfo() { + ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); + runningInfo.setJstack("jstack"); + String remark = "ok"; + int opaque = 123; + RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_RUNNING_INFO, null); + remotingCommand.setOpaque(opaque); + GetConsumerRunningInfoRequestHeader requestHeader = new GetConsumerRunningInfoRequestHeader(); + requestHeader.setJstackEnable(true); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(RemotingCommand.class); + CompletableFuture> future = + localProxyRelayService.processGetConsumerRunningInfo(ProxyContext.create(), remotingCommand, requestHeader); + future.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, remark, runningInfo)); + Mockito.verify(nettyRemotingServerMock, Mockito.times(1)) + .processResponseCommand(Mockito.any(SimpleChannelHandlerContext.class), argumentCaptor.capture()); + RemotingCommand remotingCommand1 = argumentCaptor.getValue(); + assertThat(remotingCommand1.getCode()).isEqualTo(ResponseCode.SUCCESS); + assertThat(remotingCommand1.getRemark()).isEqualTo(remark); + assertThat(remotingCommand1.getBody()).isEqualTo(runningInfo.encode()); + } + + @Test + public void testProcessConsumeMessageDirectly() { + ConsumeMessageDirectlyResultRequestHeader requestHeader = new ConsumeMessageDirectlyResultRequestHeader(); + String remark = "ok"; + int opaque = 123; + RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.CONSUME_MESSAGE_DIRECTLY, null); + remotingCommand.setOpaque(opaque); + ConsumeMessageDirectlyResult result = new ConsumeMessageDirectlyResult(); + result.setConsumeResult(CMResult.CR_SUCCESS); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(RemotingCommand.class); + CompletableFuture> future = + localProxyRelayService.processConsumeMessageDirectly(ProxyContext.create(), remotingCommand, requestHeader); + future.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, remark, result)); + Mockito.verify(nettyRemotingServerMock, Mockito.times(1)) + .processResponseCommand(Mockito.any(SimpleChannelHandlerContext.class), argumentCaptor.capture()); + RemotingCommand remotingCommand1 = argumentCaptor.getValue(); + assertThat(remotingCommand1.getCode()).isEqualTo(ResponseCode.SUCCESS); + assertThat(remotingCommand1.getRemark()).isEqualTo(remark); + assertThat(remotingCommand1.getBody()).isEqualTo(result.encode()); + } +} \ No newline at end of file From ad5dc3fd46cdca7cb83f479a8926635183ca8a18 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 25 May 2022 17:41:52 +0800 Subject: [PATCH 214/338] [ISSUE #3949] add QueueSelector test cases --- .../consumer/ReceiveMessageActivityTest.java | 57 +++++++++++ .../v2/producer/SendMessageActivityTest.java | 94 +++++++++++++++++++ 2 files changed, 151 insertions(+) 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 ae5bef6eec..e9a5457cdd 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 @@ -28,15 +28,27 @@ import apache.rocketmq.v2.Settings; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.PermName; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -48,6 +60,9 @@ import static org.mockito.Mockito.when; public class ReceiveMessageActivityTest extends BaseActivityTest { + protected static final String BROKER_NAME = "broker"; + protected static final String CLUSTER_NAME = "cluster"; + protected static final String BROKER_ADDR = "127.0.0.1:10911"; private static final String TOPIC = "topic"; private static final String CONSUMER_GROUP = "consumerGroup"; private ReceiveMessageActivity receiveMessageActivity; @@ -120,4 +135,46 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { ); assertEquals(Code.MESSAGE_NOT_FOUND, responseArgumentCaptor.getValue().getStatus().getCode()); } + + @Test + public void testReceiveMessageQueueSelector() { + TopicRouteData topicRouteData = new TopicRouteData(); + List queueDatas = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + QueueData queueData = new QueueData(); + queueData.setBrokerName(BROKER_NAME + i); + queueData.setReadQueueNums(1); + queueData.setPerm(PermName.PERM_READ); + queueDatas.add(queueData); + } + topicRouteData.setQueueDatas(queueDatas); + + List brokerDatas = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + BrokerData brokerData = new BrokerData(); + brokerData.setCluster(CLUSTER_NAME); + brokerData.setBrokerName(BROKER_NAME + i); + HashMap brokerAddrs = new HashMap<>(); + brokerAddrs.put(MixAll.MASTER_ID, BROKER_ADDR); + brokerData.setBrokerAddrs(brokerAddrs); + brokerDatas.add(brokerData); + } + topicRouteData.setBrokerDatas(brokerDatas); + + MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData); + ReceiveMessageActivity.ReceiveMessageQueueSelector selector = new ReceiveMessageActivity.ReceiveMessageQueueSelector(""); + + SelectableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); + SelectableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); + SelectableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); + + assertEquals(firstSelect, thirdSelect); + assertNotEquals(firstSelect, secondSelect); + + for (int i = 0; i < 2; i++) { + ReceiveMessageActivity.ReceiveMessageQueueSelector selectorBrokerName = + new ReceiveMessageActivity.ReceiveMessageQueueSelector(BROKER_NAME + i); + assertEquals(BROKER_NAME + i, selectorBrokerName.select(ProxyContext.create(), messageQueueView).getBrokerName()); + } + } } \ No newline at end of file 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 a23fdd5612..782aaa5e51 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 @@ -28,29 +28,41 @@ import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.ByteString; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import java.util.HashMap; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.route.BrokerData; +import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; public class SendMessageActivityTest extends BaseActivityTest { + protected static final String BROKER_NAME = "broker"; + protected static final String CLUSTER_NAME = "cluster"; + protected static final String BROKER_ADDR = "127.0.0.1:10911"; private static final String TOPIC = "topic"; private static final String CONSUMER_GROUP = "consumerGroup"; @@ -239,4 +251,86 @@ public class SendMessageActivityTest extends BaseActivityTest { assertEquals(MessageClientIDSetter.getUniqID(messageExt), msgId); assertEquals(MessageSysFlag.TRANSACTION_PREPARED_TYPE | MessageSysFlag.COMPRESSED_FLAG, messageExt.getSysFlag()); } + + @Test + public void testSendOrderMessageQueueSelector() { + TopicRouteData topicRouteData = new TopicRouteData(); + QueueData queueData = new QueueData(); + BrokerData brokerData = new BrokerData(); + queueData.setBrokerName(BROKER_NAME); + queueData.setWriteQueueNums(8); + queueData.setPerm(PermName.PERM_WRITE); + topicRouteData.setQueueDatas(Lists.newArrayList(queueData)); + brokerData.setCluster(CLUSTER_NAME); + brokerData.setBrokerName(BROKER_NAME); + HashMap brokerAddrs = new HashMap<>(); + brokerAddrs.put(MixAll.MASTER_ID, BROKER_ADDR); + brokerData.setBrokerAddrs(brokerAddrs); + topicRouteData.setBrokerDatas(Lists.newArrayList(brokerData)); + + MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData); + SendMessageActivity.SendMessageQueueSelector selector1 = new SendMessageActivity.SendMessageQueueSelector( + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageGroup(String.valueOf(1)) + .build()) + .build()) + .build() + ); + + SendMessageActivity.SendMessageQueueSelector selector2 = new SendMessageActivity.SendMessageQueueSelector( + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageGroup(String.valueOf(1)) + .build()) + .build()) + .build() + ); + + SendMessageActivity.SendMessageQueueSelector selector3 = new SendMessageActivity.SendMessageQueueSelector( + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setSystemProperties(SystemProperties.newBuilder() + .setMessageGroup(String.valueOf(2)) + .build()) + .build()) + .build() + ); + + assertEquals(selector1.select(ProxyContext.create(), messageQueueView), selector2.select(ProxyContext.create(), messageQueueView)); + assertNotEquals(selector1.select(ProxyContext.create(), messageQueueView), selector3.select(ProxyContext.create(), messageQueueView)); + } + + @Test + public void testSendNormalMessageQueueSelector() { + TopicRouteData topicRouteData = new TopicRouteData(); + QueueData queueData = new QueueData(); + BrokerData brokerData = new BrokerData(); + queueData.setBrokerName(BROKER_NAME); + queueData.setWriteQueueNums(2); + queueData.setPerm(PermName.PERM_WRITE); + topicRouteData.setQueueDatas(Lists.newArrayList(queueData)); + brokerData.setCluster(CLUSTER_NAME); + brokerData.setBrokerName(BROKER_NAME); + HashMap brokerAddrs = new HashMap<>(); + brokerAddrs.put(MixAll.MASTER_ID, BROKER_ADDR); + 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() + ); + + SelectableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); + SelectableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); + SelectableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); + + assertEquals(firstSelect, thirdSelect); + assertNotEquals(firstSelect, secondSelect); + } } \ No newline at end of file From 31a50fe83a505fa1195ab72c56d7d68a51f31726 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 19:21:26 +0800 Subject: [PATCH 215/338] [ISSUE #3949] Add unit test for ClientActivity --- .../proxy/grpc/v2/client/ClientActivity.java | 8 ++ .../grpc/v2/client/ClientActivityTest.java | 86 ++++++++++++++++++- 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 341f3fef8f..6ea8f5450e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -82,6 +82,14 @@ public class ClientActivity extends AbstractMessingActivity { this.init(); } + ClientActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager, + GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager); + this.grpcChannelManager = grpcChannelManager; + this.init(); + } + protected void init() { this.messagingProcessor.registerConsumerListener(new ConsumerIdsChangeListenerImpl()); this.messagingProcessor.registerProducerListener(new ProducerChangeListenerImpl()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index f8597c3f32..b295cbb477 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -31,33 +31,60 @@ import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; import apache.rocketmq.v2.SubscriptionEntry; import apache.rocketmq.v2.TelemetryCommand; +import apache.rocketmq.v2.ThreadStackTrace; +import apache.rocketmq.v2.VerifyMessageResult; import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.CMResult; +import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; +import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.remoting.protocol.LanguageCode; import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +@RunWith(MockitoJUnitRunner.class) public class ClientActivityTest extends BaseActivityTest { private static final String TOPIC = "topic"; private static final String CONSUMER_GROUP = "consumerGroup"; private ClientActivity clientActivity; + @Mock + private GrpcChannelManager grpcChannelManagerMock; + @Mock + private CompletableFuture> runningInfoFutureMock; + @Captor + ArgumentCaptor> runningInfoArgumentCaptor; + @Mock + private CompletableFuture> resultFutureMock; + @Captor + ArgumentCaptor> resultArgumentCaptor; @Before public void before() throws Throwable { @@ -153,7 +180,6 @@ public class ClientActivityTest extends BaseActivityTest { subscriptionDatasArgumentCaptor.capture() ); - HeartbeatResponse response = this.sendConsumerHeartbeat(context); assertEquals(Code.OK, response.getStatus().getCode()); @@ -227,6 +253,64 @@ public class ClientActivityTest extends BaseActivityTest { assertClientChannelInfo(clientChannelInfo, CONSUMER_GROUP); } + @Test + public void testReportThreadStackTrace() { + this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager, grpcChannelManagerMock); + String jstack = "jstack"; + String nonce = "123"; + when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) runningInfoFutureMock); + Context context = createContext(); + StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { + @Override public void onNext(TelemetryCommand value) { + } + + @Override public void onError(Throwable t) { + } + + @Override public void onCompleted() { + } + }); + streamObserver.onNext(TelemetryCommand.newBuilder() + .setThreadStackTrace(ThreadStackTrace.newBuilder() + .setThreadStackTrace(jstack) + .setNonce(nonce) + .build()) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + verify(runningInfoFutureMock, times(1)).complete(runningInfoArgumentCaptor.capture()); + ProxyRelayResult result = runningInfoArgumentCaptor.getValue(); + assertThat(result.getCode()).isEqualTo(ResponseCode.SUCCESS); + assertThat(result.getResult().getJstack()).isEqualTo(jstack); + } + + @Test + public void testReportVerifyMessageResult() { + this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager, grpcChannelManagerMock); + String nonce = "123"; + when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) resultFutureMock); + Context context = createContext(); + StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { + @Override public void onNext(TelemetryCommand value) { + } + + @Override public void onError(Throwable t) { + } + + @Override public void onCompleted() { + } + }); + streamObserver.onNext(TelemetryCommand.newBuilder() + .setVerifyMessageResult(VerifyMessageResult.newBuilder() + .setNonce(nonce) + .build()) + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); + verify(resultFutureMock, times(1)).complete(resultArgumentCaptor.capture()); + ProxyRelayResult result = resultArgumentCaptor.getValue(); + assertThat(result.getCode()).isEqualTo(ResponseCode.SUCCESS); + assertThat(result.getResult().getConsumeResult()).isEqualTo(CMResult.CR_SUCCESS); + } + protected CompletableFuture sendClientTelemetry(Context ctx, Settings settings) { when(grpcClientSettingsManager.getClientSettings(any())).thenReturn(settings); From d741618c0c7e44cd77665dbcc19238d3ec470d4d Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 19:21:49 +0800 Subject: [PATCH 216/338] [ISSUE #3949] Remove unused code in GrpcConverter --- .../proxy/grpc/v2/common/GrpcConverter.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 04169146b0..72db47eccf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -35,7 +35,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; @@ -230,18 +229,4 @@ public class GrpcConverter { .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) .build(); } - - public static TopicMessageType buildTopicMessageType(MessageType messageType) { - if (messageType.equals(MessageType.NORMAL)) { - return TopicMessageType.NORMAL; - } else if (messageType.equals(MessageType.FIFO)) { - return TopicMessageType.FIFO; - } else if (messageType.equals(MessageType.DELAY)) { - return TopicMessageType.DELAY; - } else if (messageType.equals(MessageType.TRANSACTION)) { - return TopicMessageType.TRANSACTION; - } else { - return TopicMessageType.UNSPECIFIED; - } - } } From e7bb6d7ee3d58965ab232f5c5d9f70b6710023cf Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 25 May 2022 19:32:14 +0800 Subject: [PATCH 217/338] [ISSUE #3949] Add GrpcConverterTest --- .../grpc/v2/common/GrpcConverterTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java new file mode 100644 index 0000000000..9c743d8422 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.grpc.v2.common; + +import apache.rocketmq.v2.MessageQueue; +import org.apache.rocketmq.common.message.MessageExt; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GrpcConverterTest { + @Test + public void testBuildMessageQueue() { + String topic = "topic"; + String brokerName = "brokerName"; + int queueId = 1; + MessageExt messageExt = new MessageExt(); + messageExt.setQueueId(queueId); + messageExt.setTopic(topic); + + MessageQueue messageQueue = GrpcConverter.buildMessageQueue(messageExt, brokerName); + assertThat(messageQueue.getTopic().getName()).isEqualTo(topic); + assertThat(messageQueue.getBroker().getName()).isEqualTo(brokerName); + assertThat(messageQueue.getId()).isEqualTo(queueId); + } +} \ No newline at end of file From 7fbe6e26e0a8d847b9de88cab0d28599756ee9c0 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 26 May 2022 12:12:42 +0800 Subject: [PATCH 218/338] [ISSUE #3949] Add stack info when internal error --- .../rocketmq/proxy/common/utils/ExceptionUtils.java | 10 ++++++++++ .../rocketmq/proxy/grpc/v2/common/ResponseBuilder.java | 2 +- .../org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 8 +++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java index 78b32e4cb0..b4b9ad9189 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java @@ -29,4 +29,14 @@ public class ExceptionUtils { } return throwable; } + + public static String getErrorDetailMessage(Throwable t) { + StringBuilder sb = new StringBuilder(); + sb.append(t.getMessage()).append(". ").append(t.getClass().getSimpleName()); + + if (t.getStackTrace().length > 0) { + sb.append(". ").append(t.getStackTrace()[0]); + } + return sb.toString(); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java index c0c275f5b5..b68e1a77f9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java @@ -42,7 +42,7 @@ public class ResponseBuilder { } log.error("internal server error", t); - return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "internal error"); + return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, ExceptionUtils.getErrorDetailMessage(t)); } public static Status buildStatus(Code code, String message) { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 28e50452ff..b7e98d6a8f 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -537,7 +537,8 @@ public class GrpcBaseIT extends BaseConf { } public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { - assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getStatus().getCode()) + .withFailMessage("%s", response.getStatus().getMessage()).isEqualTo(Code.OK); assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); assertThat(response.getMessageQueues(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } @@ -549,8 +550,9 @@ public class GrpcBaseIT extends BaseConf { } public void assertSendMessage(SendMessageResponse response, String messageId) { - assertThat(response.getStatus() - .getCode()).isEqualTo(Code.OK); + assertThat(response.getStatus().getCode()) + .withFailMessage("%s", response.getStatus().getMessage()) + .isEqualTo(Code.OK); assertThat(response.getEntries(0).getMessageId()).isEqualTo(messageId); } From 76c4fe7844581362b184e43288bee6bf0cf55cc3 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 26 May 2022 14:12:08 +0800 Subject: [PATCH 219/338] [ISSUE #3949] assert Status when IT --- .../org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index b7e98d6a8f..32fb1bf331 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -97,6 +97,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.apache.rocketmq.test.util.MQRandomUtils; @@ -537,22 +538,19 @@ public class GrpcBaseIT extends BaseConf { } public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { - assertThat(response.getStatus().getCode()) - .withFailMessage("%s", response.getStatus().getMessage()).isEqualTo(Code.OK); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); assertThat(response.getMessageQueues(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } public void assertQueryAssignment(QueryAssignmentResponse response, int assignmentCount) { - assertThat(response.getStatus().getCode()).isEqualTo(Code.OK); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); assertThat(response.getAssignmentsCount()).isEqualTo(assignmentCount); assertThat(response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } public void assertSendMessage(SendMessageResponse response, String messageId) { - assertThat(response.getStatus().getCode()) - .withFailMessage("%s", response.getStatus().getMessage()) - .isEqualTo(Code.OK); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); assertThat(response.getEntries(0).getMessageId()).isEqualTo(messageId); } From e54dad0eb0abd05e046249d2a60c24f6a9acf6d9 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 26 May 2022 15:26:21 +0800 Subject: [PATCH 220/338] [ISSUE #3949] Debug travis ci --- .../java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java | 1 + .../test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index b19f56fd84..064eb063a0 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -41,6 +41,7 @@ public class ClusterGrpcIT extends GrpcBaseIT { @Before public void setUp() throws Exception { super.setUp(); + ConfigurationManager.getProxyConfig().setEnableTopicMessageTypeCheck(false); ConfigurationManager.getProxyConfig().setTransactionHeartbeatPeriodSecond(3); messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); messagingProcessor.start(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 94073ff454..3c9e154bc6 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -23,7 +23,6 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.ServiceManager; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -36,6 +35,7 @@ public class LocalGrpcIT extends GrpcBaseIT { @Before public void setUp() throws Exception { super.setUp(); + ConfigurationManager.getProxyConfig().setEnableTopicMessageTypeCheck(false); messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); messagingProcessor.start(); grpcMessagingApplication = GrpcMessagingApplication.create(messagingProcessor); From a2e50fbd03e20b8c74a5c00478ba6439ac708946 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 26 May 2022 21:20:35 +0800 Subject: [PATCH 221/338] [ISSUE #3949] Refine test process to solve IntegrationTest issue * Optimize create topic check process and remove retry logic * Add waitBrokerRegistered to BaseConf constructor * Optimize waitBrokerRegistered logic --- pom.xml | 5 ++ test/pom.xml | 16 ++--- .../rocketmq/test/util/MQAdminTestUtils.java | 19 ++---- .../apache/rocketmq/test/base/BaseConf.java | 11 +++- .../test/base/IntegrationTestBase.java | 59 +++++-------------- .../dledger/DLedgerProduceAndConsumeIT.java | 2 +- 6 files changed, 37 insertions(+), 75 deletions(-) diff --git a/pom.xml b/pom.xml index b29d63409b..93f58dac08 100644 --- a/pom.xml +++ b/pom.xml @@ -671,6 +671,11 @@ protobuf-java-util 3.20.1 + + org.awaitility + awaitility + 4.1.0 + diff --git a/test/pom.xml b/test/pom.xml index f0d292a15b..6d6df5b080 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -61,18 +61,6 @@ truth 0.30 - - org.mockito - mockito-core - 2.28.2 - test - - - junit - junit - 4.12 - test - ${project.groupId} rocketmq-client @@ -86,6 +74,10 @@ grpc-testing test + + org.awaitility + awaitility + diff --git a/test/src/main/java/org/apache/rocketmq/test/util/MQAdminTestUtils.java b/test/src/main/java/org/apache/rocketmq/test/util/MQAdminTestUtils.java index d376cd0a12..2e449dee7b 100644 --- a/test/src/main/java/org/apache/rocketmq/test/util/MQAdminTestUtils.java +++ b/test/src/main/java/org/apache/rocketmq/test/util/MQAdminTestUtils.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.test.util; +import java.util.concurrent.TimeUnit; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; @@ -50,19 +51,19 @@ import java.util.UUID; import java.util.concurrent.ForkJoinPool; import static org.apache.rocketmq.common.statictopic.TopicQueueMappingUtils.getMappingDetailFromConfig; +import static org.awaitility.Awaitility.await; public class MQAdminTestUtils { private static Logger log = Logger.getLogger(MQAdminTestUtils.class); public static boolean createTopic(String nameSrvAddr, String clusterName, String topic, int queueNum, Map attributes) { - int defaultWaitTime = 5; + int defaultWaitTime = 30; return createTopic(nameSrvAddr, clusterName, topic, queueNum, attributes, defaultWaitTime); } public static boolean createTopic(String nameSrvAddr, String clusterName, String topic, int queueNum, Map attributes, int waitTimeSec) { - boolean createResult = false; DefaultMQAdminExt mqAdminExt = new DefaultMQAdminExt(); mqAdminExt.setInstanceName(UUID.randomUUID().toString()); mqAdminExt.setNamesrvAddr(nameSrvAddr); @@ -72,19 +73,9 @@ public class MQAdminTestUtils { } catch (Exception e) { } - long startTime = System.currentTimeMillis(); - while (!createResult) { - createResult = checkTopicExist(mqAdminExt, topic); - if (System.currentTimeMillis() - startTime < waitTimeSec * 1000) { - TestUtils.waitForMoment(100); - } else { - log.error(String.format("timeout,but create topic[%s] failed!", topic)); - break; - } - } - + await().atMost(waitTimeSec, TimeUnit.SECONDS).until(() -> checkTopicExist(mqAdminExt, topic)); ForkJoinPool.commonPool().execute(mqAdminExt::shutdown); - return createResult; + return true; } private static boolean checkTopicExist(DefaultMQAdminExt mqAdminExt, String topic) { diff --git a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java index cd8d8aafd6..0f26f2042c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/BaseConf.java @@ -93,7 +93,8 @@ public class BaseConf { } public BaseConf() { - + // Add waitBrokerRegistered to BaseConf constructor to make it default for all subclasses. + waitBrokerRegistered(nsAddr, clusterName, brokerNum); } // This method can't be placed in the static block of BaseConf, which seems to lead to a strange dead lock. @@ -102,9 +103,13 @@ public class BaseConf { mqAdminExt.setNamesrvAddr(nsAddr); try { mqAdminExt.start(); - Thread.sleep(10000); await().atMost(30, TimeUnit.SECONDS).until(() -> { - List brokerDatas = mqAdminExt.examineTopicRouteInfo(clusterName).getBrokerDatas(); + List brokerDatas; + try { + brokerDatas = mqAdminExt.examineTopicRouteInfo(clusterName).getBrokerDatas(); + } catch (Exception e) { + return false; + } return brokerDatas.size() == expectedBrokerNum; }); for (BrokerController brokerController: brokerControllerList) { diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java index 305275948b..9b09d16320 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.common.BrokerConfig; @@ -41,7 +42,6 @@ import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.NettyServerConfig; import org.apache.rocketmq.store.config.MessageStoreConfig; import org.apache.rocketmq.test.util.MQAdminTestUtils; -import org.apache.rocketmq.test.util.TestUtils; public class IntegrationTestBase { public static InternalLogger logger = InternalLoggerFactory.getLogger(IntegrationTestBase.class); @@ -52,7 +52,7 @@ public class IntegrationTestBase { protected static final List TMPE_FILES = new ArrayList<>(); protected static final List BROKER_CONTROLLERS = new ArrayList<>(); protected static final List NAMESRV_CONTROLLERS = new ArrayList<>(); - protected static int topicCreateTime = 30 * 1000; + protected static int topicCreateTime = (int) TimeUnit.SECONDS.toSeconds(30); public static volatile int COMMIT_LOG_SIZE = 1024 * 1024 * 100; protected static final int INDEX_NUM = 1000; @@ -169,60 +169,29 @@ public class IntegrationTestBase { return brokerController; } - public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, TopicMessageType topicMessageType) { - long startTime = System.currentTimeMillis(); - boolean createResult; - - while (true) { - Map attributes = new HashMap<>(); - attributes.put("+" + TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), topicMessageType.toString()); - createResult = MQAdminTestUtils.createTopic(nsAddr, clusterName, topic, queueNumbers, attributes); - if (createResult) { - break; - } else if (System.currentTimeMillis() - startTime > topicCreateTime) { - Truth.assertWithMessage(String.format("topic[%s] is created failed after:%d ms", topic, - System.currentTimeMillis() - startTime)).fail(); - break; - } else { - TestUtils.waitForMoment(500); - continue; - } - } - - return createResult; + public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, CQType cqType) { + return initTopic(topic, nsAddr, clusterName, queueNumbers, cqType, TopicMessageType.NORMAL); } - public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, CQType cqType) { - long startTime = System.currentTimeMillis(); + public static boolean initTopic(String topic, String nsAddr, String clusterName, int queueNumbers, CQType cqType, TopicMessageType topicMessageType) { boolean createResult; - - while (true) { - Map attributes = new HashMap<>(); - if (!Objects.equals(CQType.SimpleCQ, cqType)) { - attributes.put("+" + TopicAttributes.QUEUE_TYPE_ATTRIBUTE.getName(), cqType.toString()); - } - createResult = MQAdminTestUtils.createTopic(nsAddr, clusterName, topic, queueNumbers, attributes); - if (createResult) { - break; - } else if (System.currentTimeMillis() - startTime > topicCreateTime) { - Truth.assertWithMessage(String.format("topic[%s] is created failed after:%d ms", topic, - System.currentTimeMillis() - startTime)).fail(); - break; - } else { - TestUtils.waitForMoment(500); - continue; - } + Map attributes = new HashMap<>(); + if (!Objects.equals(CQType.SimpleCQ, cqType)) { + attributes.put("+" + TopicAttributes.QUEUE_TYPE_ATTRIBUTE.getName(), cqType.toString()); } - + if (!Objects.equals(TopicMessageType.NORMAL, topicMessageType)) { + attributes.put("+" + TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName(), topicMessageType.toString()); + } + createResult = MQAdminTestUtils.createTopic(nsAddr, clusterName, topic, queueNumbers, attributes, topicCreateTime); return createResult; } public static boolean initTopic(String topic, String nsAddr, String clusterName, CQType cqType) { - return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, cqType); + return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, cqType, TopicMessageType.NORMAL); } public static boolean initTopic(String topic, String nsAddr, String clusterName, TopicMessageType topicMessageType) { - return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, topicMessageType); + return initTopic(topic, nsAddr, clusterName, BaseConf.QUEUE_NUMBERS, CQType.SimpleCQ, topicMessageType); } public static void deleteFile(File file) { diff --git a/test/src/test/java/org/apache/rocketmq/test/base/dledger/DLedgerProduceAndConsumeIT.java b/test/src/test/java/org/apache/rocketmq/test/base/dledger/DLedgerProduceAndConsumeIT.java index 0e1bf2658b..7b9b9e5f33 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/dledger/DLedgerProduceAndConsumeIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/dledger/DLedgerProduceAndConsumeIT.java @@ -75,7 +75,7 @@ public class DLedgerProduceAndConsumeIT { BrokerConfig brokerConfig = buildBrokerConfig(cluster, brokerName); MessageStoreConfig storeConfig = buildStoreConfig(brokerName, peers, selfId); BrokerController brokerController = IntegrationTestBase.createAndStartBroker(storeConfig, brokerConfig); - Thread.sleep(3000); + BaseConf.waitBrokerRegistered(BaseConf.nsAddr, brokerConfig.getBrokerName(), 1); Assert.assertEquals(BrokerRole.SYNC_MASTER, storeConfig.getBrokerRole()); From 9e1f2f99c6aa7a7f71e4c3a03196335e70c994eb Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 11:14:12 +0800 Subject: [PATCH 222/338] [ISSUE #3949] Change topicCreateTime to 60 --- .../java/org/apache/rocketmq/test/base/IntegrationTestBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java index 9b09d16320..f41e31391f 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java @@ -52,7 +52,7 @@ public class IntegrationTestBase { protected static final List TMPE_FILES = new ArrayList<>(); protected static final List BROKER_CONTROLLERS = new ArrayList<>(); protected static final List NAMESRV_CONTROLLERS = new ArrayList<>(); - protected static int topicCreateTime = (int) TimeUnit.SECONDS.toSeconds(30); + protected static int topicCreateTime = (int) TimeUnit.SECONDS.toSeconds(60); public static volatile int COMMIT_LOG_SIZE = 1024 * 1024 * 100; protected static final int INDEX_NUM = 1000; From 66ce5e539332ebc1db6120d25ae54986572f1b2b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 11:26:05 +0800 Subject: [PATCH 223/338] Revert "[ISSUE #3949] Debug travis ci" This reverts commit fd855216da18f7d8ce674662ba9e94658a3fc205. --- .../java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java | 1 - .../test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index 064eb063a0..b19f56fd84 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -41,7 +41,6 @@ public class ClusterGrpcIT extends GrpcBaseIT { @Before public void setUp() throws Exception { super.setUp(); - ConfigurationManager.getProxyConfig().setEnableTopicMessageTypeCheck(false); ConfigurationManager.getProxyConfig().setTransactionHeartbeatPeriodSecond(3); messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); messagingProcessor.start(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 3c9e154bc6..94073ff454 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -23,6 +23,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.service.ServiceManager; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -35,7 +36,6 @@ public class LocalGrpcIT extends GrpcBaseIT { @Before public void setUp() throws Exception { super.setUp(); - ConfigurationManager.getProxyConfig().setEnableTopicMessageTypeCheck(false); messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); messagingProcessor.start(); grpcMessagingApplication = GrpcMessagingApplication.create(messagingProcessor); From 3bbca727aec8d59e34b6830a7be9bba9ed6b6b2e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 11:27:02 +0800 Subject: [PATCH 224/338] [ISSUE #3949] Remove unused method --- .../proxy/grpc/v2/producer/SendMessageActivity.java | 12 ------------ 1 file changed, 12 deletions(-) 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 d12d51953a..998c0276fb 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 @@ -241,18 +241,6 @@ public class SendMessageActivity extends AbstractMessingActivity { return builder.build(); } - protected MessageType parseMessageType(List messageList) { - MessageType messageType = messageList.get(0).getSystemProperties().getMessageType(); - for (Message message : messageList) { - MessageType messageType0 = message.getSystemProperties().getMessageType(); - if (messageType0 != messageType) { - throw new GrpcProxyException(Code.ILLEGAL_MESSAGE, "message type is not match"); - } - messageType = messageType0; - } - return messageType; - } - protected static class SendMessageQueueSelector implements QueueSelector { private final SendMessageRequest request; From 36a6e3c581b2f8a97d499aa54a00ead045ef195e Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 11:31:36 +0800 Subject: [PATCH 225/338] Revert "[ISSUE #3949] Change topicCreateTime to 60" This reverts commit 04151bdbe4f5eba04323b87c7073e2b79a8b3bee. --- .../java/org/apache/rocketmq/test/base/IntegrationTestBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java index f41e31391f..9b09d16320 100644 --- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java +++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java @@ -52,7 +52,7 @@ public class IntegrationTestBase { protected static final List TMPE_FILES = new ArrayList<>(); protected static final List BROKER_CONTROLLERS = new ArrayList<>(); protected static final List NAMESRV_CONTROLLERS = new ArrayList<>(); - protected static int topicCreateTime = (int) TimeUnit.SECONDS.toSeconds(60); + protected static int topicCreateTime = (int) TimeUnit.SECONDS.toSeconds(30); public static volatile int COMMIT_LOG_SIZE = 1024 * 1024 * 100; protected static final int INDEX_NUM = 1000; From e9948ddfea49aa4bdad9747491f6ec6ab8eee5d1 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 13:14:25 +0800 Subject: [PATCH 226/338] [ISSUE #3949] Fix testTransactionCheckThenCommit --- .../test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 32fb1bf331..08937dc1e8 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -262,7 +262,7 @@ public class GrpcBaseIT extends BaseConf { SendMessageResponse sendResponse = blockingStub.sendMessage(buildTransactionSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); - await().atMost(java.time.Duration.ofSeconds(90)).until(() -> { + await().atMost(java.time.Duration.ofMinutes(2)).until(() -> { if (telemetryCommandRef.get() == null) { return false; } From 74366de8d081363b2ba33aa720c1374e0ef89675 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 14:16:57 +0800 Subject: [PATCH 227/338] [ISSUE #3949] Add FixMethodOrder for gRPC IT --- .../java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java | 3 +++ .../java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index b19f56fd84..8fcd9f3323 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -29,10 +29,13 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.test.util.MQAdminTestUtils; import org.junit.After; import org.junit.Before; +import org.junit.FixMethodOrder; import org.junit.Test; +import org.junit.runners.MethodSorters; import static org.awaitility.Awaitility.await; +@FixMethodOrder(value = MethodSorters.NAME_ASCENDING) public class ClusterGrpcIT extends GrpcBaseIT { private MessagingProcessor messagingProcessor; diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 94073ff454..5aa188329e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -23,11 +23,13 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.GrpcMessagingApplication; import org.apache.rocketmq.proxy.processor.DefaultMessagingProcessor; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.proxy.service.ServiceManager; import org.junit.After; import org.junit.Before; +import org.junit.FixMethodOrder; import org.junit.Test; +import org.junit.runners.MethodSorters; +@FixMethodOrder(value = MethodSorters.NAME_ASCENDING) public class LocalGrpcIT extends GrpcBaseIT { private MessagingProcessor messagingProcessor; From a59a8ad046c39a4277c2d61af486df550e5e36dd Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 27 May 2022 16:56:59 +0800 Subject: [PATCH 228/338] [ISSUE #3949] send heartbeat int transactionIT --- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 08937dc1e8..53477c16c4 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -242,16 +242,14 @@ public class GrpcBaseIT extends BaseConf { requestStreamObserver.onNext(TelemetryCommand.newBuilder() .setSettings(buildProducerClientSettings(topic)) .build()); - blockingStub.heartbeat(HeartbeatRequest.newBuilder() - .setGroup(Resource.newBuilder() - .setName(group) - .build()) - .build()); + blockingStub.heartbeat(buildHeartbeatRequest(group)); await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { if (telemetryCommandRef.get() == null) { + blockingStub.heartbeat(buildHeartbeatRequest(group)); return false; } if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.SETTINGS) { + blockingStub.heartbeat(buildHeartbeatRequest(group)); return false; } return telemetryCommandRef.get() != null; @@ -264,9 +262,11 @@ public class GrpcBaseIT extends BaseConf { await().atMost(java.time.Duration.ofMinutes(2)).until(() -> { if (telemetryCommandRef.get() == null) { + blockingStub.heartbeat(buildHeartbeatRequest(group)); return false; } if (telemetryCommandRef.get().getCommandCase() != TelemetryCommand.CommandCase.RECOVER_ORPHANED_TRANSACTION_COMMAND) { + blockingStub.heartbeat(buildHeartbeatRequest(group)); return false; } return telemetryCommandRef.get() != null; @@ -295,6 +295,14 @@ public class GrpcBaseIT extends BaseConf { } } + public HeartbeatRequest buildHeartbeatRequest(String group) { + return HeartbeatRequest.newBuilder() + .setGroup(Resource.newBuilder() + .setName(group) + .build()) + .build(); + } + public void testSimpleConsumerSendAndRecv() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); From ade67ba81e716797f301e2738d4be574a3d04fd4 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 27 May 2022 14:42:01 +0800 Subject: [PATCH 229/338] [ISSUE #3949] Add GrpcMessagingApplicationTest --- .../grpc/v2/GrpcMessagingApplicationTest.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java new file mode 100644 index 0000000000..5fc223787c --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -0,0 +1,82 @@ +/* + * 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.grpc.v2; + +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; +import apache.rocketmq.v2.MessageQueue; +import apache.rocketmq.v2.QueryRouteRequest; +import apache.rocketmq.v2.QueryRouteResponse; +import apache.rocketmq.v2.Resource; +import io.grpc.Context; +import io.grpc.stub.StreamObserver; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.awaitility.Awaitility.await; + +@RunWith(MockitoJUnitRunner.class) +public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { + @Mock + StreamObserver queryRouteResponseStreamObserver; + @Mock + GrpcMessingActivity grpcMessingActivity; + GrpcMessagingApplication grpcMessagingApplication; + + private static final String TOPIC = "topic"; + private static Endpoints GRPC_ENDPOINTS = Endpoints.newBuilder() + .setScheme(AddressScheme.IPv4) + .addAddresses(Address.newBuilder().setHost("127.0.0.1").setPort(8080).build()) + .addAddresses(Address.newBuilder().setHost("127.0.0.2").setPort(8080).build()) + .build(); + + @Before + public void setUp() throws Throwable { + super.before(); + grpcMessagingApplication = new GrpcMessagingApplication(grpcMessingActivity); + } + + @Test + public void testQueryRoute() { + CompletableFuture future = new CompletableFuture<>(); + QueryRouteRequest request = QueryRouteRequest.newBuilder() + .setEndpoints(GRPC_ENDPOINTS) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .build(); + Mockito.when(grpcMessingActivity.queryRoute(Mockito.any(Context.class), Mockito.eq(request))) + .thenReturn(future); + QueryRouteResponse response = QueryRouteResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .addMessageQueues(MessageQueue.getDefaultInstance()) + .build(); + grpcMessagingApplication.queryRoute(request, queryRouteResponseStreamObserver); + future.complete(response); + await().untilAsserted(() -> { + Mockito.verify(queryRouteResponseStreamObserver, Mockito.times(1)).onNext(response); + }); + } +} \ No newline at end of file From 3685fdaaeb6cf08a6a9b78b985b464bb097f32f8 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 30 May 2022 10:45:06 +0800 Subject: [PATCH 230/338] [ISSUE #3949] Refector AuthenticationInterceptor --- .../apache/rocketmq/acl/AccessValidator.java | 4 +-- ...aHeader.java => AuthenticationHeader.java} | 34 +++++++++---------- .../acl/plain/PlainAccessResource.java | 4 +-- .../acl/plain/PlainAccessValidator.java | 4 +-- .../AuthenticationInterceptor.java | 21 +++++++----- 5 files changed, 36 insertions(+), 31 deletions(-) rename acl/src/main/java/org/apache/rocketmq/acl/common/{MetadataHeader.java => AuthenticationHeader.java} (80%) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java index 8602525b36..6bce3584ca 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/AccessValidator.java @@ -20,7 +20,7 @@ package org.apache.rocketmq.acl; import com.google.protobuf.GeneratedMessageV3; import java.util.List; import java.util.Map; -import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.common.AuthenticationHeader; import org.apache.rocketmq.common.AclConfig; import org.apache.rocketmq.common.DataVersion; import org.apache.rocketmq.common.PlainAccessConfig; @@ -43,7 +43,7 @@ public interface AccessValidator { * @param header * @return Plain access resource */ - AccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header); + AccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header); /** * Validate the access resource. diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java similarity index 80% rename from acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java rename to acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java index 96c7ac7790..52289d55df 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/MetadataHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java @@ -17,7 +17,7 @@ package org.apache.rocketmq.acl.common; -public class MetadataHeader { +public class AuthenticationHeader { private String remoteAddress; private String tenantId; private String namespace; @@ -30,7 +30,7 @@ public class MetadataHeader { private String protocol; private int requestCode; - MetadataHeader(final String remoteAddress, final String tenantId, final String namespace, + AuthenticationHeader(final String remoteAddress, final String tenantId, final String namespace, final String authorization, final String datetime, final String sessionToken, final String requestId, final String language, final String clientVersion, final String protocol, final int requestCode) { this.remoteAddress = remoteAddress; @@ -62,70 +62,70 @@ public class MetadataHeader { MetadataHeaderBuilder() { } - public MetadataHeader.MetadataHeaderBuilder remoteAddress(final String remoteAddress) { + public AuthenticationHeader.MetadataHeaderBuilder remoteAddress(final String remoteAddress) { this.remoteAddress = remoteAddress; return this; } - public MetadataHeader.MetadataHeaderBuilder tenantId(final String tenantId) { + public AuthenticationHeader.MetadataHeaderBuilder tenantId(final String tenantId) { this.tenantId = tenantId; return this; } - public MetadataHeader.MetadataHeaderBuilder namespace(final String namespace) { + public AuthenticationHeader.MetadataHeaderBuilder namespace(final String namespace) { this.namespace = namespace; return this; } - public MetadataHeader.MetadataHeaderBuilder authorization(final String authorization) { + public AuthenticationHeader.MetadataHeaderBuilder authorization(final String authorization) { this.authorization = authorization; return this; } - public MetadataHeader.MetadataHeaderBuilder datetime(final String datetime) { + public AuthenticationHeader.MetadataHeaderBuilder datetime(final String datetime) { this.datetime = datetime; return this; } - public MetadataHeader.MetadataHeaderBuilder sessionToken(final String sessionToken) { + public AuthenticationHeader.MetadataHeaderBuilder sessionToken(final String sessionToken) { this.sessionToken = sessionToken; return this; } - public MetadataHeader.MetadataHeaderBuilder requestId(final String requestId) { + public AuthenticationHeader.MetadataHeaderBuilder requestId(final String requestId) { this.requestId = requestId; return this; } - public MetadataHeader.MetadataHeaderBuilder language(final String language) { + public AuthenticationHeader.MetadataHeaderBuilder language(final String language) { this.language = language; return this; } - public MetadataHeader.MetadataHeaderBuilder clientVersion(final String clientVersion) { + public AuthenticationHeader.MetadataHeaderBuilder clientVersion(final String clientVersion) { this.clientVersion = clientVersion; return this; } - public MetadataHeader.MetadataHeaderBuilder protocol(final String protocol) { + public AuthenticationHeader.MetadataHeaderBuilder protocol(final String protocol) { this.protocol = protocol; return this; } - public MetadataHeader.MetadataHeaderBuilder requestCode(final int requestCode) { + public AuthenticationHeader.MetadataHeaderBuilder requestCode(final int requestCode) { this.requestCode = requestCode; return this; } - public MetadataHeader build() { - return new MetadataHeader(this.remoteAddress, this.tenantId, this.namespace, this.authorization, + public AuthenticationHeader build() { + return new AuthenticationHeader(this.remoteAddress, this.tenantId, this.namespace, this.authorization, this.datetime, this.sessionToken, this.requestId, this.language, this.clientVersion, this.protocol, this.requestCode); } } - public static MetadataHeader.MetadataHeaderBuilder builder() { - return new MetadataHeader.MetadataHeaderBuilder(); + public static AuthenticationHeader.MetadataHeaderBuilder builder() { + return new AuthenticationHeader.MetadataHeaderBuilder(); } public String getRemoteAddress() { diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java index a879360bb4..fdc48534ab 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java @@ -36,7 +36,7 @@ import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.AclUtils; import org.apache.rocketmq.acl.common.AuthorizationHeader; -import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.common.AuthenticationHeader; import org.apache.rocketmq.acl.common.Permission; import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.common.MixAll; @@ -172,7 +172,7 @@ public class PlainAccessResource implements AccessResource { return accessResource; } - public static PlainAccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header) { + public static PlainAccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header) { PlainAccessResource accessResource = new PlainAccessResource(); String remoteAddress = header.getRemoteAddress(); if (remoteAddress != null && remoteAddress.contains(":")) { diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java index 99c2bd5699..749e366e26 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessValidator.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.Map; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; -import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.common.AuthenticationHeader; import org.apache.rocketmq.common.AclConfig; import org.apache.rocketmq.common.DataVersion; import org.apache.rocketmq.common.PlainAccessConfig; @@ -40,7 +40,7 @@ public class PlainAccessValidator implements AccessValidator { return PlainAccessResource.parse(request, remoteAddr); } - @Override public AccessResource parse(GeneratedMessageV3 messageV3, MetadataHeader header) { + @Override public AccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header) { return PlainAccessResource.parse(messageV3, header); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index 5d3fc0f105..5c3969a5f4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -30,12 +30,12 @@ import java.util.List; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.AccessValidator; import org.apache.rocketmq.acl.common.AclException; -import org.apache.rocketmq.acl.common.MetadataHeader; +import org.apache.rocketmq.acl.common.AuthenticationHeader; import org.apache.rocketmq.acl.plain.PlainAccessResource; import org.apache.rocketmq.proxy.config.ConfigurationManager; public class AuthenticationInterceptor implements ServerInterceptor { - private final List accessValidatorList; + protected final List accessValidatorList; public AuthenticationInterceptor(List accessValidatorList) { this.accessValidatorList = accessValidatorList; @@ -50,7 +50,7 @@ public class AuthenticationInterceptor implements ServerInterceptor { if (ConfigurationManager.getProxyConfig().isEnableACL()) { try { GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; - MetadataHeader metadataHeader = MetadataHeader.builder() + AuthenticationHeader authenticationHeader = AuthenticationHeader.builder() .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) .authorization(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.AUTHORIZATION)) @@ -62,11 +62,8 @@ public class AuthenticationInterceptor implements ServerInterceptor { .protocol(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.PROTOCOL_VERSION)) .requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName())) .build(); - for (AccessValidator accessValidator : accessValidatorList) { - AccessResource accessResource = accessValidator.parse(messageV3, metadataHeader); - accessValidator.validate(accessResource); - addHeader(headers, messageV3, accessResource); - } + + validate(authenticationHeader, headers, messageV3); super.onMessage(message); } catch (AclException aclException) { throw new StatusRuntimeException(Status.PERMISSION_DENIED, headers); @@ -78,6 +75,14 @@ public class AuthenticationInterceptor implements ServerInterceptor { }; } + protected void validate(AuthenticationHeader authenticationHeader, Metadata headers, GeneratedMessageV3 messageV3) { + for (AccessValidator accessValidator : accessValidatorList) { + AccessResource accessResource = accessValidator.parse(messageV3, authenticationHeader); + accessValidator.validate(accessResource); + addHeader(headers, messageV3, accessResource); + } + } + protected void addHeader(Metadata headers, GeneratedMessageV3 messageV3, AccessResource accessResource) { headers.put(InterceptorConstants.RPC_NAME, messageV3.getDescriptorForType().getFullName()); if (accessResource instanceof PlainAccessResource) { From 74b8084268654ae0c3bf48c39999a6c54e11dc24 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 31 May 2022 17:51:45 +0800 Subject: [PATCH 231/338] [ISSUE #3949] change toString to toStringHelper --- .../header/AckMessageRequestHeader.java | 15 ++++---- .../ChangeInvisibleTimeRequestHeader.java | 20 +++++------ .../CheckTransactionStateRequestHeader.java | 17 ++++----- .../header/CloneGroupOffsetRequestHeader.java | 13 +++---- ...umeMessageDirectlyResultRequestHeader.java | 19 +++++----- .../ConsumerSendMsgBackRequestHeader.java | 19 +++++----- .../CreateAccessConfigRequestHeader.java | 21 +++++------ .../header/CreateTopicRequestHeader.java | 25 ++++++------- .../header/EndTransactionRequestHeader.java | 19 +++++----- .../header/GetConsumeStatsRequestHeader.java | 9 ++--- .../GetConsumerListByGroupRequestHeader.java | 7 ++-- .../GetConsumerRunningInfoRequestHeader.java | 11 +++--- .../GetConsumerStatusRequestHeader.java | 11 +++--- .../header/GetMaxOffsetRequestHeader.java | 11 +++--- .../header/GetMinOffsetRequestHeader.java | 9 ++--- .../header/PopMessageRequestHeader.java | 27 +++++++------- .../header/PullMessageRequestHeader.java | 29 +++++++-------- .../header/SearchOffsetRequestHeader.java | 11 +++--- .../header/SendMessageRequestHeader.java | 31 ++++++++-------- .../header/SendMessageRequestHeaderV2.java | 20 +++++++++++ .../UpdateConsumerOffsetRequestHeader.java | 13 +++---- .../service/route/MessageQueueSelector.java | 16 +++++---- .../service/route/SelectableMessageQueue.java | 9 ++--- .../service/transaction/TransactionId.java | 35 +++++++++---------- 24 files changed, 229 insertions(+), 188 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java index 66721a4903..a8fea34d94 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/AckMessageRequestHeader.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -80,12 +81,12 @@ public class AckMessageRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "AckMessageRequestHeader{" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - ", queueId=" + queueId + - ", extraInfo='" + extraInfo + '\'' + - ", offset=" + offset + - '}'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .add("queueId", queueId) + .add("extraInfo", extraInfo) + .add("offset", offset) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java index 6c6f5bad9f..918a2304b7 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ChangeInvisibleTimeRequestHeader.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -94,15 +95,14 @@ public class ChangeInvisibleTimeRequestHeader implements CommandCustomHeader { this.queueId = queueId; } - @Override - public String toString() { - return "ChangeInvisibleTimeRequestHeader{" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - ", queueId=" + queueId + - ", extraInfo='" + extraInfo + '\'' + - ", offset=" + offset + - ", invisibleTime=" + invisibleTime + - '}'; + @Override public String toString() { + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .add("queueId", queueId) + .add("extraInfo", extraInfo) + .add("offset", offset) + .add("invisibleTime", invisibleTime) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java index 6671a9d773..b04f7ef812 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -88,13 +89,13 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "CheckTransactionStateRequestHeader{" + - "brokerName='" + brokerName + '\'' + - ", tranStateTableOffset=" + tranStateTableOffset + - ", commitLogOffset=" + commitLogOffset + - ", msgId='" + msgId + '\'' + - ", transactionId='" + transactionId + '\'' + - ", offsetMsgId='" + offsetMsgId + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("brokerName", brokerName) + .add("tranStateTableOffset", tranStateTableOffset) + .add("commitLogOffset", commitLogOffset) + .add("msgId", msgId) + .add("transactionId", transactionId) + .add("offsetMsgId", offsetMsgId) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java index e010649a4b..3b478f8a11 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CloneGroupOffsetRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -71,11 +72,11 @@ public class CloneGroupOffsetRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "CloneGroupOffsetRequestHeader{" + - "srcGroup='" + srcGroup + '\'' + - ", destGroup='" + destGroup + '\'' + - ", topic='" + topic + '\'' + - ", offline=" + offline + - '}'; + return MoreObjects.toStringHelper(this) + .add("srcGroup", srcGroup) + .add("destGroup", destGroup) + .add("topic", topic) + .add("offline", offline) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java index 18298a6ea5..a7dc28e256 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumeMessageDirectlyResultRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -100,14 +101,14 @@ public class ConsumeMessageDirectlyResultRequestHeader implements CommandCustomH @Override public String toString() { - return "ConsumeMessageDirectlyResultRequestHeader{" + - "consumerGroup='" + consumerGroup + '\'' + - ", clientId='" + clientId + '\'' + - ", msgId='" + msgId + '\'' + - ", brokerName='" + brokerName + '\'' + - ", topic='" + topic + '\'' + - ", topicSysFlag=" + topicSysFlag + - ", groupSysFlag=" + groupSysFlag + - '}'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("clientId", clientId) + .add("msgId", msgId) + .add("brokerName", brokerName) + .add("topic", topic) + .add("topicSysFlag", topicSysFlag) + .add("groupSysFlag", groupSysFlag) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java index 2e0a120a15..3d65f23921 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -98,14 +99,14 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "ConsumerSendMsgBackRequestHeader{" + - "offset=" + offset + - ", group='" + group + '\'' + - ", delayLevel=" + delayLevel + - ", originMsgId='" + originMsgId + '\'' + - ", originTopic='" + originTopic + '\'' + - ", unitMode=" + unitMode + - ", maxReconsumeTimes=" + maxReconsumeTimes + - '}'; + return MoreObjects.toStringHelper(this) + .add("offset", offset) + .add("group", group) + .add("delayLevel", delayLevel) + .add("originMsgId", originMsgId) + .add("originTopic", originTopic) + .add("unitMode", unitMode) + .add("maxReconsumeTimes", maxReconsumeTimes) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java index c91ab11101..09a2a0c667 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateAccessConfigRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -113,15 +114,15 @@ public class CreateAccessConfigRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "CreateAccessConfigRequestHeader{" + - "accessKey='" + accessKey + '\'' + - ", secretKey='" + secretKey + '\'' + - ", whiteRemoteAddress='" + whiteRemoteAddress + '\'' + - ", admin=" + admin + - ", defaultTopicPerm='" + defaultTopicPerm + '\'' + - ", defaultGroupPerm='" + defaultGroupPerm + '\'' + - ", topicPerms='" + topicPerms + '\'' + - ", groupPerms='" + groupPerms + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("accessKey", accessKey) + .add("secretKey", secretKey) + .add("whiteRemoteAddress", whiteRemoteAddress) + .add("admin", admin) + .add("defaultTopicPerm", defaultTopicPerm) + .add("defaultGroupPerm", defaultGroupPerm) + .add("topicPerms", topicPerms) + .add("groupPerms", groupPerms) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java index 05c7195ac0..43859410ae 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CreateTopicRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.TopicFilterType; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; @@ -142,17 +143,17 @@ public class CreateTopicRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "CreateTopicRequestHeader{" + - "topic='" + topic + '\'' + - ", defaultTopic='" + defaultTopic + '\'' + - ", readQueueNums=" + readQueueNums + - ", writeQueueNums=" + writeQueueNums + - ", perm=" + perm + - ", topicFilterType='" + topicFilterType + '\'' + - ", topicSysFlag=" + topicSysFlag + - ", order=" + order + - ", attributes='" + attributes + '\'' + - ", force=" + force + - '}'; + return MoreObjects.toStringHelper(this) + .add("topic", topic) + .add("defaultTopic", defaultTopic) + .add("readQueueNums", readQueueNums) + .add("writeQueueNums", writeQueueNums) + .add("perm", perm) + .add("topicFilterType", topicFilterType) + .add("topicSysFlag", topicSysFlag) + .add("order", order) + .add("attributes", attributes) + .add("force", force) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java index 87661c320a..80fdc3d4a6 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/EndTransactionRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; @@ -118,14 +119,14 @@ public class EndTransactionRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "EndTransactionRequestHeader{" + - "producerGroup='" + producerGroup + '\'' + - ", tranStateTableOffset=" + tranStateTableOffset + - ", commitLogOffset=" + commitLogOffset + - ", commitOrRollback=" + commitOrRollback + - ", fromTransactionCheck=" + fromTransactionCheck + - ", msgId='" + msgId + '\'' + - ", transactionId='" + transactionId + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("producerGroup", producerGroup) + .add("tranStateTableOffset", tranStateTableOffset) + .add("commitLogOffset", commitLogOffset) + .add("commitOrRollback", commitOrRollback) + .add("fromTransactionCheck", fromTransactionCheck) + .add("msgId", msgId) + .add("transactionId", transactionId) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java index 7ce48bcee5..69a2fc60d0 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumeStatsRequestHeader.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -47,9 +48,9 @@ public class GetConsumeStatsRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "GetConsumeStatsRequestHeader{" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java index 3a8c482147..ecab653150 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -39,8 +40,8 @@ public class GetConsumerListByGroupRequestHeader implements CommandCustomHeader @Override public String toString() { - return "GetConsumerListByGroupRequestHeader [" + - "consumerGroup='" + consumerGroup + '\'' + - ']'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java index 5f9bee4e93..840716f5a3 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerRunningInfoRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -60,10 +61,10 @@ public class GetConsumerRunningInfoRequestHeader implements CommandCustomHeader @Override public String toString() { - return "GetConsumerRunningInfoRequestHeader{" + - "consumerGroup='" + consumerGroup + '\'' + - ", clientId='" + clientId + '\'' + - ", jstackEnable=" + jstackEnable + - '}'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("clientId", clientId) + .add("jstackEnable", jstackEnable) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java index d77acda8cd..0a983fecf6 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerStatusRequestHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -60,10 +61,10 @@ public class GetConsumerStatusRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "GetConsumerStatusRequestHeader{" + - "topic='" + topic + '\'' + - ", group='" + group + '\'' + - ", clientAddr='" + clientAddr + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("topic", topic) + .add("group", group) + .add("clientAddr", clientAddr) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java index 1883eecc12..f98e8500dd 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -74,10 +75,10 @@ public class GetMaxOffsetRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "GetMaxOffsetRequestHeader [" + - "topic='" + topic + '\'' + - ", queueId=" + queueId + - ", committed=" + committed + - ']'; + return MoreObjects.toStringHelper(this) + .add("topic", topic) + .add("queueId", queueId) + .add("committed", committed) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java index b205326f67..d54c4aa41c 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -56,9 +57,9 @@ public class GetMinOffsetRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "GetMinOffsetRequestHeader [" + - "topic='" + topic + '\'' + - ", queueId=" + queueId + - ']'; + return MoreObjects.toStringHelper(this) + .add("topic", topic) + .add("queueId", queueId) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java index c90a26a334..a3a186a917 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PopMessageRequestHeader.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -155,18 +156,18 @@ public class PopMessageRequestHeader implements CommandCustomHeader { @Override public String toString() { - return "PopMessageRequestHeader [" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - ", queueId=" + queueId + - ", maxMsgNums=" + maxMsgNums + - ", invisibleTime=" + invisibleTime + - ", pollTime=" + pollTime + - ", bornTime=" + bornTime + - ", initMode=" + initMode + - ", expType='" + expType + '\'' + - ", exp='" + exp + '\'' + - ", order=" + order + - ']'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .add("queueId", queueId) + .add("maxMsgNums", maxMsgNums) + .add("invisibleTime", invisibleTime) + .add("pollTime", pollTime) + .add("bornTime", bornTime) + .add("initMode", initMode) + .add("expType", expType) + .add("exp", exp) + .add("order", order) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java index bbcd813973..77a17f3d0c 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -157,19 +158,19 @@ public class PullMessageRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "PullMessageRequestHeader [" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - ", queueId=" + queueId + - ", queueOffset=" + queueOffset + - ", maxMsgBytes=" + maxMsgBytes + - ", maxMsgNums=" + maxMsgNums + - ", sysFlag=" + sysFlag + - ", commitOffset=" + commitOffset + - ", suspendTimeoutMillis=" + suspendTimeoutMillis + - ", subscription='" + subscription + '\'' + - ", subVersion=" + subVersion + - ", expressionType='" + expressionType + '\'' + - ']'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .add("queueId", queueId) + .add("queueOffset", queueOffset) + .add("maxMsgBytes", maxMsgBytes) + .add("maxMsgNums", maxMsgNums) + .add("sysFlag", sysFlag) + .add("commitOffset", commitOffset) + .add("suspendTimeoutMillis", suspendTimeoutMillis) + .add("subscription", subscription) + .add("subVersion", subVersion) + .add("expressionType", expressionType) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java index 1fcab60db5..3753e062b7 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -67,10 +68,10 @@ public class SearchOffsetRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "SearchOffsetRequestHeader [" + - "topic='" + topic + '\'' + - ", queueId=" + queueId + - ", timestamp=" + timestamp + - ']'; + return MoreObjects.toStringHelper(this) + .add("topic", topic) + .add("queueId", queueId) + .add("timestamp", timestamp) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java index cc4db84032..abea27e502 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -166,20 +167,20 @@ public class SendMessageRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "SendMessageRequestHeader [" + - "producerGroup='" + producerGroup + '\'' + - ", topic='" + topic + '\'' + - ", defaultTopic='" + defaultTopic + '\'' + - ", defaultTopicQueueNums=" + defaultTopicQueueNums + - ", queueId=" + queueId + - ", sysFlag=" + sysFlag + - ", bornTimestamp=" + bornTimestamp + - ", flag=" + flag + - ", properties='" + properties + '\'' + - ", reconsumeTimes=" + reconsumeTimes + - ", unitMode=" + unitMode + - ", batch=" + batch + - ", maxReconsumeTimes=" + maxReconsumeTimes + - ']'; + return MoreObjects.toStringHelper(this) + .add("producerGroup", producerGroup) + .add("topic", topic) + .add("defaultTopic", defaultTopic) + .add("defaultTopicQueueNums", defaultTopicQueueNums) + .add("queueId", queueId) + .add("sysFlag", sysFlag) + .add("bornTimestamp", bornTimestamp) + .add("flag", flag) + .add("properties", properties) + .add("reconsumeTimes", reconsumeTimes) + .add("unitMode", unitMode) + .add("batch", batch) + .add("maxReconsumeTimes", maxReconsumeTimes) + .toString(); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java index 4e0098b5f0..5c9394e0cc 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; @@ -197,4 +198,23 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader { public void setM(boolean m) { this.m = m; } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("a", a) + .add("b", b) + .add("c", c) + .add("d", d) + .add("e", e) + .add("f", f) + .add("g", g) + .add("h", h) + .add("i", i) + .add("j", j) + .add("k", k) + .add("l", l) + .add("m", m) + .toString(); + } } \ No newline at end of file diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java index 5b47211e67..77af812184 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java @@ -20,6 +20,7 @@ */ package org.apache.rocketmq.common.protocol.header; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; @@ -76,11 +77,11 @@ public class UpdateConsumerOffsetRequestHeader extends TopicQueueRequestHeader { @Override public String toString() { - return "UpdateConsumerOffsetRequestHeader [" + - "consumerGroup='" + consumerGroup + '\'' + - ", topic='" + topic + '\'' + - ", queueId=" + queueId + - ", commitOffset=" + commitOffset + - ']'; + return MoreObjects.toStringHelper(this) + .add("consumerGroup", consumerGroup) + .add("topic", topic) + .add("queueId", queueId) + .add("commitOffset", commitOffset) + .toString(); } } 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 4c4ccdc49a..7c2f40a6e0 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 @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service.route; +import com.google.common.base.MoreObjects; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -192,12 +193,13 @@ public class MessageQueueSelector { return Objects.hash(queues, brokerActingQueues); } - @Override - public String toString() { - return "SelectableMessageQueue{" + "queues=" + queues + - ", brokers=" + brokerActingQueues + - ", queueIndex=" + queueIndex + - ", brokerIndex=" + brokerIndex + - '}'; + @Override public String toString() { + return MoreObjects.toStringHelper(this) + .add("queues", queues) + .add("brokerActingQueues", brokerActingQueues) + .add("brokerNameQueueMap", brokerNameQueueMap) + .add("queueIndex", queueIndex) + .add("brokerIndex", brokerIndex) + .toString(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java index 88446c7195..85f7434aed 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service.route; +import com.google.common.base.MoreObjects; import java.util.Objects; import org.apache.rocketmq.common.message.MessageQueue; @@ -72,9 +73,9 @@ public class SelectableMessageQueue implements Comparable Date: Wed, 1 Jun 2022 11:10:18 +0800 Subject: [PATCH 232/338] [ISSUE #3949] setDeliveryTimestamp when complete ReceiveMessageResponse --- .../proxy/grpc/v2/common/ResponseWriter.java | 47 +++++++---------- .../v2/consumer/ReceiveMessageActivity.java | 22 ++++---- .../ReceiveMessageResponseStreamWriter.java | 52 +++++++++++++------ .../consumer/ReceiveMessageActivityTest.java | 13 ++++- ...eceiveMessageResponseStreamWriterTest.java | 10 ++-- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 23 -------- 6 files changed, 86 insertions(+), 81 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java index 1f63734932..dd2be5f872 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java @@ -17,9 +17,10 @@ package org.apache.rocketmq.proxy.grpc.v2.common; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; -import java.util.Iterator; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -27,41 +28,31 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - public static void write(StreamObserver observer, final Iterator response) { - while (response.hasNext()) { - writeResponse(observer, response.next()); - } - observer.onCompleted(); - } - public static void write(StreamObserver observer, final T response) { - writeResponse(observer, response); - observer.onCompleted(); + if (writeResponse(observer, response)) { + observer.onCompleted(); + } } - public static void writeResponse(StreamObserver observer, final T response) { + public static boolean writeResponse(StreamObserver observer, final T response) { if (null == response) { - return; - } - if (isCancelled(observer)) { - log.warn("client has cancelled the request. response to write: {}", response); - return; + return false; } log.debug("start to write response. response: {}", response); - observer.onNext(response); - } - - public static void writeException(StreamObserver observer, final Throwable e) { - if (null == e) { - return; - } if (isCancelled(observer)) { - log.warn("Client has cancelled the request. Exception to write", e); - return; + log.warn("client has cancelled the request. response to write: {}", response); + return false; } - log.debug("Start to write error response", e); - observer.onError(e); - observer.onCompleted(); + try { + observer.onNext(response); + } catch (StatusRuntimeException statusRuntimeException) { + if (Status.CANCELLED.equals(statusRuntimeException.getStatus())) { + log.warn("client has cancelled the request. response to write: {}", response); + return false; + } + throw statusRuntimeException; + } + return true; } public static boolean isCancelled(StreamObserver observer) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index f3965037a8..0bd8bf565a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -51,10 +51,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { ProxyContext proxyContext = createContext(ctx); - ReceiveMessageResponseStreamWriter writer = new ReceiveMessageResponseStreamWriter( - this.messagingProcessor, - responseObserver - ); + ReceiveMessageResponseStreamWriter writer = createWriter(proxyContext, responseObserver); try { Settings settings = this.grpcClientSettingsManager.getClientSettings(proxyContext); @@ -67,7 +64,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { pollTime = timeRemaining; } if (pollTime <= 0) { - writer.write(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); + writer.writeAndComplete(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); return; } @@ -85,7 +82,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), GrpcConverter.buildExpressionType(filterExpression.getType())); } catch (Exception e) { - writer.write(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); + writer.writeAndComplete(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); return; } @@ -104,16 +101,23 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { fifo, new PopMessageResultFilterImpl(grpcClientSettingsManager), timeRemaining - ).thenAccept(popResult -> writer.write(proxyContext, request, popResult)) + ).thenAccept(popResult -> writer.writeAndComplete(proxyContext, request, popResult)) .exceptionally(t -> { - writer.write(proxyContext, request, t); + writer.writeAndComplete(proxyContext, request, t); return null; }); } catch (Throwable t) { - writer.write(proxyContext, request, t); + writer.writeAndComplete(proxyContext, request, t); } } + protected ReceiveMessageResponseStreamWriter createWriter(ProxyContext ctx, StreamObserver responseObserver) { + return new ReceiveMessageResponseStreamWriter( + this.messagingProcessor, + responseObserver + ); + } + protected static class ReceiveMessageQueueSelector implements QueueSelector { private final String brokerName; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java index 52514ef0ef..054e9d23e0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -20,14 +20,18 @@ import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; +import com.google.protobuf.util.Timestamps; import io.grpc.stub.StreamObserver; import java.time.Duration; import java.util.Iterator; import java.util.List; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; @@ -35,7 +39,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class ReceiveMessageResponseStreamWriter { - + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected static final long NACK_INVISIBLE_TIME = Duration.ofSeconds(1).toMillis(); protected final MessagingProcessor messagingProcessor; @@ -48,7 +52,7 @@ public class ReceiveMessageResponseStreamWriter { this.streamObserver = observer; } - public void write(ProxyContext ctx, ReceiveMessageRequest request, PopResult popResult) { + public void writeAndComplete(ProxyContext ctx, ReceiveMessageRequest request, PopResult popResult) { PopStatus status = popResult.getPopStatus(); List messageFoundList = popResult.getMsgFoundList(); try { @@ -62,7 +66,7 @@ public class ReceiveMessageResponseStreamWriter { streamObserver.onNext(ReceiveMessageResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .build()); - Iterator messageIterator = messageFoundList.iterator(); + Iterator messageIterator = messageFoundList.iterator(); while (messageIterator.hasNext()) { MessageExt curMessageExt = messageIterator.next(); Message curMessage = convertToMessage(curMessageExt); @@ -93,9 +97,10 @@ public class ReceiveMessageResponseStreamWriter { break; } } catch (Throwable t) { - write(ctx, request, t); + writeResponseWithErrorIgnore( + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(t)).build()); } finally { - streamObserver.onCompleted(); + onComplete(); } } @@ -121,17 +126,34 @@ public class ReceiveMessageResponseStreamWriter { ); } - public void write(ProxyContext ctx, Code code, String message) { - ResponseWriter.write( - streamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(code, message)).build() - ); + public void writeAndComplete(ProxyContext ctx, Code code, String message) { + writeResponseWithErrorIgnore( + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(code, message)).build()); + onComplete(); } - public void write(ProxyContext ctx, ReceiveMessageRequest request, Throwable throwable) { - ResponseWriter.write( - streamObserver, - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build() - ); + public void writeAndComplete(ProxyContext ctx, ReceiveMessageRequest request, Throwable throwable) { + writeResponseWithErrorIgnore( + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build()); + onComplete(); + } + + protected void writeResponseWithErrorIgnore(ReceiveMessageResponse response) { + try { + ResponseWriter.writeResponse(streamObserver, response); + } catch (Exception e) { + log.error("err when write receive message response", e); + } + } + + protected void onComplete() { + writeResponseWithErrorIgnore(ReceiveMessageResponse.newBuilder() + .setDeliveryTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .build()); + try { + streamObserver.onCompleted(); + } catch (Exception e) { + log.error("err when complete receive message response", e); + } } } 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 e9a5457cdd..412e5806c9 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 @@ -94,7 +94,7 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { receiveStreamObserver ); - assertEquals(Code.ILLEGAL_FILTER_EXPRESSION, responseArgumentCaptor.getValue().getStatus().getCode()); + assertEquals(Code.ILLEGAL_FILTER_EXPRESSION, getResponseCodeFromReceiveMessageResponseList(responseArgumentCaptor.getAllValues())); } @Test @@ -133,7 +133,16 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { .build(), receiveStreamObserver ); - assertEquals(Code.MESSAGE_NOT_FOUND, responseArgumentCaptor.getValue().getStatus().getCode()); + assertEquals(Code.MESSAGE_NOT_FOUND, getResponseCodeFromReceiveMessageResponseList(responseArgumentCaptor.getAllValues())); + } + + private Code getResponseCodeFromReceiveMessageResponseList(List responseList) { + for (ReceiveMessageResponse response : responseList) { + if (response.hasStatus()) { + return response.getStatus().getCode(); + } + } + return null; } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java index 1855220a5e..8086b37b36 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriterTest.java @@ -90,7 +90,7 @@ public class ReceiveMessageResponseStreamWriterTest extends BaseActivityTest { messageExtList.add(createMessageExt(TOPIC, "tag")); messageExtList.add(createMessageExt(TOPIC, "tag")); PopResult popResult = new PopResult(PopStatus.FOUND, messageExtList); - writer.write( + writer.writeAndComplete( ProxyContext.create(), ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) @@ -104,7 +104,7 @@ public class ReceiveMessageResponseStreamWriterTest extends BaseActivityTest { ); verify(streamObserver, times(1)).onCompleted(); - verify(streamObserver, times(3)).onNext(any()); + verify(streamObserver, times(4)).onNext(any()); verify(this.messagingProcessor, times(1)) .changeInvisibleTime(any(), any(), anyString(), anyString(), anyString(), anyLong()); @@ -122,7 +122,7 @@ public class ReceiveMessageResponseStreamWriterTest extends BaseActivityTest { doNothing().when(streamObserver).onNext(responseArgumentCaptor.capture()); PopResult popResult = new PopResult(PopStatus.POLLING_FULL, new ArrayList<>()); - writer.write( + writer.writeAndComplete( ProxyContext.create(), ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) @@ -135,7 +135,9 @@ public class ReceiveMessageResponseStreamWriterTest extends BaseActivityTest { popResult ); - assertEquals(Code.TOO_MANY_REQUESTS, responseArgumentCaptor.getValue().getStatus().getCode()); + ReceiveMessageResponse response = responseArgumentCaptor.getAllValues().stream().filter(ReceiveMessageResponse::hasStatus) + .findFirst().get(); + assertEquals(Code.TOO_MANY_REQUESTS, response.getStatus().getCode()); } private static MessageExt createMessageExt(String topic, String tags) { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 53477c16c4..f1f79bfcdf 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -502,14 +502,6 @@ public class GrpcBaseIT extends BaseConf { .build(); } - public AckMessageRequest buildAckMessageRequest(String topic, String group, String messageId, - String receiptHandle) { - return buildAckMessageRequest(topic, group, AckMessageEntry.newBuilder() - .setMessageId(messageId) - .setReceiptHandle(receiptHandle) - .build()); - } - public AckMessageRequest buildAckMessageRequest(String topic, String group, AckMessageEntry... entry) { return AckMessageRequest.newBuilder() .setGroup(Resource.newBuilder() @@ -572,15 +564,6 @@ public class GrpcBaseIT extends BaseConf { return response.get(1).getMessage(); } - public void assertAllAckOk(AckMessageResponse response) { - assertThat(response.getStatus() - .getCode()).isEqualTo(Code.OK); - for (AckMessageResultEntry entry : response.getEntriesList()) { - assertThat(entry.getStatus() - .getCode()).isEqualTo(Code.OK); - } - } - public void assertRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand command, String messageId) { assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) .isEqualTo(messageId); @@ -606,12 +589,6 @@ public class GrpcBaseIT extends BaseConf { .build(); } - public Settings buildAccessPointClientSettings(int port) { - return Settings.newBuilder() - .setAccessPoint(buildEndpoints(port)) - .build(); - } - public Settings buildSimpleConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { return Settings.newBuilder() .setClientType(ClientType.SIMPLE_CONSUMER) From e3658d8a4384df8fd747e805c506f7b5f501409a Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 1 Jun 2022 11:23:51 +0800 Subject: [PATCH 233/338] [ISSUE #3949] change toString to toStringHelper --- .../acl/common/AuthenticationHeader.java | 29 ++++++++++--------- .../acl/common/AuthorizationHeader.java | 13 +++++---- .../broker/client/ProducerChangeListener.java | 5 ++++ .../common/thread/ThreadPoolWrapper.java | 16 ++++------ .../proxy/service/route/MessageQueueView.java | 14 ++++----- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java index 52289d55df..00112d7374 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthenticationHeader.java @@ -17,6 +17,8 @@ package org.apache.rocketmq.acl.common; +import com.google.common.base.MoreObjects; + public class AuthenticationHeader { private String remoteAddress; private String tenantId; @@ -217,19 +219,18 @@ public class AuthenticationHeader { } @Override public String toString() { - final StringBuilder sb = new StringBuilder("MetadataHeader{"); - sb.append("remoteAddress='").append(remoteAddress).append('\''); - sb.append(", tenantId='").append(tenantId).append('\''); - sb.append(", namespace='").append(namespace).append('\''); - sb.append(", authorization='").append(authorization).append('\''); - sb.append(", datetime='").append(datetime).append('\''); - sb.append(", sessionToken='").append(sessionToken).append('\''); - sb.append(", requestId='").append(requestId).append('\''); - sb.append(", language='").append(language).append('\''); - sb.append(", clientVersion='").append(clientVersion).append('\''); - sb.append(", protocol='").append(protocol).append('\''); - sb.append(", requestCode=").append(requestCode); - sb.append('}'); - return sb.toString(); + return MoreObjects.toStringHelper(this) + .add("remoteAddress", remoteAddress) + .add("tenantId", tenantId) + .add("namespace", namespace) + .add("authorization", authorization) + .add("datetime", datetime) + .add("sessionToken", sessionToken) + .add("requestId", requestId) + .add("language", language) + .add("clientVersion", clientVersion) + .add("protocol", protocol) + .add("requestCode", requestCode) + .toString(); } } diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java index 7e0406d8d0..24eb6de8db 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.acl.common; +import com.google.common.base.MoreObjects; import java.util.Arrays; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; @@ -111,11 +112,11 @@ public class AuthorizationHeader { } @Override public String toString() { - return "AuthorizationHeader{" + - "method='" + method + '\'' + - ", accessKey='" + accessKey + '\'' + - ", signedHeaders=" + Arrays.toString(signedHeaders) + - ", signature='" + signature + '\'' + - '}'; + return MoreObjects.toStringHelper(this) + .add("method", method) + .add("accessKey", accessKey) + .add("signedHeaders", signedHeaders) + .add("signature", signature) + .toString(); } } diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java index 576faf8a81..f8183d33fa 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerChangeListener.java @@ -16,6 +16,11 @@ */ package org.apache.rocketmq.broker.client; +/** + * producer manager will call this listener when something happen + *

+ * event type: {@link ProducerGroupEvent} + */ public interface ProducerChangeListener { void handle(ProducerGroupEvent event, String group, ClientChannelInfo clientChannelInfo); diff --git a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java index 653fa1d833..3e5bbfe574 100644 --- a/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java +++ b/common/src/main/java/org/apache/rocketmq/common/thread/ThreadPoolWrapper.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.common.thread; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; @@ -110,15 +111,10 @@ public class ThreadPoolWrapper { } @Override public String toString() { - final StringBuilder sb = new StringBuilder("ThreadPoolWrapper{"); - sb.append("name='") - .append(name) - .append('\''); - sb.append(", threadPoolExecutor=") - .append(threadPoolExecutor); - sb.append(", statusPrinters=") - .append(statusPrinters); - sb.append('}'); - return sb.toString(); + return MoreObjects.toStringHelper(this) + .add("name", name) + .add("threadPoolExecutor", threadPoolExecutor) + .add("statusPrinters", statusPrinters) + .toString(); } } 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 303dfe2a77..06c9d14569 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 @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service.route; +import com.google.common.base.MoreObjects; import org.apache.rocketmq.common.protocol.route.TopicRouteData; public class MessageQueueView { @@ -52,12 +53,11 @@ public class MessageQueueView { return writeSelector; } - @Override - public String toString() { - return "MessageQueueView{" + - "readSelector=" + readSelector + - ", writeSelector=" + writeSelector + - ", topicRouteWrapper=" + topicRouteWrapper + - '}'; + @Override public String toString() { + return MoreObjects.toStringHelper(this) + .add("readSelector", readSelector) + .add("writeSelector", writeSelector) + .add("topicRouteWrapper", topicRouteWrapper) + .toString(); } } \ No newline at end of file From 3bac7de04399c7498afdba7c58f0e3d3156b4033 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 31 May 2022 20:37:05 +0800 Subject: [PATCH 234/338] [ISSUE #3949] Add error handle when telemetry --- .../grpc/v2/GrpcMessagingApplication.java | 5 ++++ .../proxy/grpc/v2/client/ClientActivity.java | 30 +++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 52cea43719..3538fd2b94 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -48,6 +48,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -55,8 +56,11 @@ import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServiceImplBase implements StartAndShutdown { + private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final GrpcMessingActivity grpcMessingActivity; @@ -345,6 +349,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void onError(Throwable t) { + log.error("telemetry onError", t); responseTelemetryCommand.onError(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 6ea8f5450e..86b9652c66 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -206,19 +206,25 @@ public class ClientActivity extends AbstractMessingActivity { return new StreamObserver() { @Override public void onNext(TelemetryCommand request) { - switch (request.getCommandCase()) { - case SETTINGS: { - responseObserver.onNext(processClientSettings(ctx, request, responseObserver)); - break; - } - case THREAD_STACK_TRACE: { - reportThreadStackTrace(ctx, request.getStatus(), request.getThreadStackTrace()); - break; - } - case VERIFY_MESSAGE_RESULT: { - reportVerifyMessageResult(ctx, request.getStatus(), request.getVerifyMessageResult()); - break; + try { + switch (request.getCommandCase()) { + case SETTINGS: { + responseObserver.onNext(processClientSettings(ctx, request, responseObserver)); + break; + } + case THREAD_STACK_TRACE: { + reportThreadStackTrace(ctx, request.getStatus(), request.getThreadStackTrace()); + break; + } + case VERIFY_MESSAGE_RESULT: { + reportVerifyMessageResult(ctx, request.getStatus(), request.getVerifyMessageResult()); + break; + } } + } catch (Exception e) { + responseObserver.onNext(TelemetryCommand.newBuilder() + .setStatus(ResponseBuilder.buildStatus(e)) + .build()); } } From 405f5aad83ed8d0ae6ffb803cb33536a4eb09530 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 1 Jun 2022 13:03:25 +0800 Subject: [PATCH 235/338] [ISSUE #3949] add log when write rejected response --- .../apache/rocketmq/acl/common/AuthorizationHeader.java | 1 - .../rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java index 24eb6de8db..aa40b6fd33 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AuthorizationHeader.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.acl.common; import com.google.common.base.MoreObjects; -import java.util.Arrays; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 3538fd2b94..806504d683 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -349,7 +349,6 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void onError(Throwable t) { - log.error("telemetry onError", t); responseTelemetryCommand.onError(t); } @@ -400,8 +399,12 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (r instanceof GrpcTask) { - GrpcTask grpcTask = (GrpcTask) r; - ResponseWriter.write(grpcTask.streamObserver, grpcTask.executeRejectResponse); + try { + GrpcTask grpcTask = (GrpcTask) r; + ResponseWriter.write(grpcTask.streamObserver, grpcTask.executeRejectResponse); + } catch (Throwable t) { + log.warn("write rejected error response failed", t); + } } } } From 73618554f23f2c6792f00f5fb0104b4ebc7005c5 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 1 Jun 2022 17:38:18 +0800 Subject: [PATCH 236/338] [ISSUE #3949] for code style --- .../rocketmq/common/constant/LoggerName.java | 1 + .../rocketmq/common/logger/ProxyLogger.java | 26 ----------------- .../common/logger/WatermarkLogger.java | 28 ------------------- .../common/thread/ThreadPoolMonitor.java | 27 ++++++++++++------ distribution/conf/logback_proxy.xml | 20 ++++++------- .../apache/rocketmq/proxy/ProxyStartup.java | 8 ++++-- .../proxy/common/ParameterConverter.java | 24 ---------------- .../proxy/common/utils/FilterUtils.java | 2 +- .../proxy/common/utils/FutureUtils.java | 3 +- .../rocketmq/proxy/config/ProxyConfig.java | 9 ++++++ .../interceptor/InterceptorConstants.java | 1 - .../grpc/v2/DefaultGrpcMessingActivity.java | 3 +- .../proxy/grpc/v2/GrpcMessingActivity.java | 12 +++++--- .../grpc/v2/channel/GrpcChannelManager.java | 4 +-- .../grpc/v2/channel/GrpcClientChannel.java | 3 +- .../proxy/grpc/v2/common/ResponseBuilder.java | 2 +- .../consumer/PopMessageResultFilterImpl.java | 3 +- .../v2/consumer/ReceiveMessageActivity.java | 3 +- .../proxy/processor/MessagingProcessor.java | 2 +- .../validator/TopicMessageTypeValidator.java | 3 +- .../proxy/service/ClusterServiceManager.java | 2 +- .../proxy/service/LocalServiceManager.java | 6 ++-- .../proxy/service/ServiceManager.java | 2 +- .../proxy/service/channel/SimpleChannel.java | 7 +++-- .../message/ClusterMessageService.java | 7 +++-- .../service/message/LocalMessageService.java | 12 +++++--- .../service/mqclient/MQClientAPIExt.java | 3 +- .../ProxyClientRemotingProcessor.java | 3 +- .../relay/ClusterProxyRelayService.java | 3 +- .../proxy/service/relay/ProxyChannel.java | 6 ++-- .../service/route/LocalTopicRouteService.java | 3 +- .../service/route/MessageQueueSelector.java | 3 +- .../proxy/service/route/MessageQueueView.java | 3 +- .../service/route/SelectableMessageQueue.java | 3 +- .../service/route/TopicRouteService.java | 6 ++-- .../ClusterTransactionService.java | 5 ++-- .../transaction/LocalTransactionService.java | 15 +++++++--- .../service/transaction/TransactionId.java | 6 ++-- .../proxy/grpc/v2/BaseActivityTest.java | 1 - .../grpc/v2/GrpcMessagingApplicationTest.java | 4 +-- .../grpc/v2/client/ClientActivityTest.java | 21 +++++++++----- .../common/GrpcClientSettingsManagerTest.java | 2 +- .../v2/consumer/AckMessageActivityTest.java | 3 +- .../ChangeInvisibleDurationActivityTest.java | 2 +- .../consumer/ReceiveMessageActivityTest.java | 1 - .../ForwardMessageToDLQActivityTest.java | 2 +- .../grpc/v2/route/RouteActivityTest.java | 28 +++++++++---------- .../EndTransactionActivityTest.java | 2 +- .../processor/ConsumerProcessorTest.java | 2 +- .../processor/ProducerProcessorTest.java | 2 +- .../metadata/ClusterMetadataServiceTest.java | 3 -- .../service/mqclient/MQClientAPIExtTest.java | 1 - .../proxy/service/relay/ProxyChannelTest.java | 11 +++++--- .../route/ClusterTopicRouteServiceTest.java | 5 ++-- .../ClusterTransactionServiceTest.java | 3 -- .../rmq-proxy-home/conf/logback_proxy.xml | 22 +++++++-------- 56 files changed, 189 insertions(+), 205 deletions(-) delete mode 100644 common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java delete mode 100644 common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java 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 244c5de772..b8ba059ea3 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 @@ -45,4 +45,5 @@ public class LoggerName { public static final String FAILOVER_LOGGER_NAME = "RocketmqFailover"; public static final String STDOUT_LOGGER_NAME = "STDOUT"; public static final String PROXY_LOGGER_NAME = "RocketmqProxy"; + public static final String PROXY_WATER_MARK_LOGGER_NAME = "RocketmqProxyWatermark"; } diff --git a/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java b/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java deleted file mode 100644 index 1e51ed9d8d..0000000000 --- a/common/src/main/java/org/apache/rocketmq/common/logger/ProxyLogger.java +++ /dev/null @@ -1,26 +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.common.logger; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ProxyLogger { - public static final Logger LOG_WATER_MARK = LoggerFactory.getLogger("Watermark"); - public static final Logger LOG_JSTACK = LoggerFactory.getLogger("Jstack"); -} diff --git a/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java b/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java deleted file mode 100644 index 9e57d02c8f..0000000000 --- a/common/src/main/java/org/apache/rocketmq/common/logger/WatermarkLogger.java +++ /dev/null @@ -1,28 +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.common.logger; - -import org.slf4j.Logger; - -public class WatermarkLogger { - private static final Logger LOG_MSG_TRACE = ProxyLogger.LOG_WATER_MARK; - - public static void info(String name, String k, double v) { - LOG_MSG_TRACE.info("\t{}\t{}\t{}", name, k, v); - } -} 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 6db0b2f15a..e5bb6a394c 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 @@ -28,22 +28,30 @@ 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.logger.ProxyLogger; -import org.apache.rocketmq.common.logger.WatermarkLogger; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; public class ThreadPoolMonitor { + private static InternalLogger jstackLogger = InternalLoggerFactory.getLogger(ThreadPoolMonitor.class); + private static InternalLogger waterMarkLogger = InternalLoggerFactory.getLogger(ThreadPoolMonitor.class); + private static final List MONITOR_EXECUTOR = new CopyOnWriteArrayList<>(); private static final ScheduledExecutorService MONITOR_SCHEDULED = Executors.newSingleThreadScheduledExecutor( new ThreadFactoryBuilder().setNameFormat("ThreadPoolMonitor-%d").build() ); + private static volatile long threadPoolStatusPeriodTime = TimeUnit.SECONDS.toMillis(3); private static volatile boolean enablePrintJstack = true; - private static volatile long jstackPeriodTIme = 60000; + private static volatile long jstackPeriodTime = 60000; private static volatile long jstackTime = System.currentTimeMillis(); - public static void config(boolean enablePrintJstack, long jstackPeriodTime) { + public static void config(InternalLogger jstackLoggerConfig, InternalLogger waterMarkLoggerConfig, + boolean enablePrintJstack, long jstackPeriodTimeConfig, long threadPoolStatusPeriodTimeConfig) { + jstackLogger = jstackLoggerConfig; + waterMarkLogger = waterMarkLoggerConfig; + threadPoolStatusPeriodTime = threadPoolStatusPeriodTimeConfig; ThreadPoolMonitor.enablePrintJstack = enablePrintJstack; - jstackPeriodTIme = jstackPeriodTime; + jstackPeriodTime = jstackPeriodTimeConfig; } public static ThreadPoolExecutor createAndMonitor(int corePoolSize, @@ -97,15 +105,15 @@ public class ThreadPoolMonitor { List monitors = threadPoolWrapper.getStatusPrinters(); for (ThreadPoolStatusMonitor monitor : monitors) { double value = monitor.value(threadPoolWrapper.getThreadPoolExecutor()); - WatermarkLogger.info(threadPoolWrapper.getName(), + waterMarkLogger.info("\t{}\t{}\t{}", threadPoolWrapper.getName(), monitor.describe(), value); if (enablePrintJstack) { if (monitor.needPrintJstack(threadPoolWrapper.getThreadPoolExecutor(), value) && - System.currentTimeMillis() - jstackTime > jstackPeriodTIme) { + System.currentTimeMillis() - jstackTime > jstackPeriodTime) { jstackTime = System.currentTimeMillis(); - ProxyLogger.LOG_JSTACK.warn("jstack start \n " + UtilAll.jstack()); + jstackLogger.warn("jstack start\n{}", UtilAll.jstack()); } } } @@ -113,7 +121,8 @@ public class ThreadPoolMonitor { } public static void init() { - MONITOR_SCHEDULED.scheduleAtFixedRate(ThreadPoolMonitor::logThreadPoolStatus, 20, 1, TimeUnit.SECONDS); + MONITOR_SCHEDULED.scheduleAtFixedRate(ThreadPoolMonitor::logThreadPoolStatus, 20, + threadPoolStatusPeriodTime, TimeUnit.MILLISECONDS); } public static void shutdown() { diff --git a/distribution/conf/logback_proxy.xml b/distribution/conf/logback_proxy.xml index 8d0458ebf0..ad862d53c7 100644 --- a/distribution/conf/logback_proxy.xml +++ b/distribution/conf/logback_proxy.xml @@ -25,7 +25,7 @@ ${user.home}/logs/rocketmqlogs/otherdays/proxy.%i.log.gz 1 - 20 + 10 128MB @@ -39,25 +39,25 @@ - - ${user.home}/logs/rocketmqlogs/grpc.log + ${user.home}/logs/rocketmqlogs/proxy_watermark.log true - ${user.home}/logs/rocketmqlogs/otherdays/grpc.%i.log.gz + ${user.home}/logs/rocketmqlogs/otherdays/proxy_watermark.%i.log.gz 1 - 20 + 10 128MB - %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + %d{yyy-MM-dd HH:mm:ss,GMT+8}%m%n UTF-8 - - + + @@ -408,9 +408,9 @@ - + - + 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 d198830e30..3eb3c26850 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -149,9 +149,13 @@ public class ProxyStartup { } public static void initThreadPoolMonitor() { - ThreadPoolMonitor.init(); ProxyConfig config = ConfigurationManager.getProxyConfig(); - ThreadPoolMonitor.config(config.isEnablePrintJstack(), config.getPrintJstackInMillis()); + ThreadPoolMonitor.config( + InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME), + InternalLoggerFactory.getLogger(LoggerName.PROXY_WATER_MARK_LOGGER_NAME), + config.isEnablePrintJstack(), config.getPrintJstackInMillis(), + config.getPrintThreadPoolStatusInMillis()); + ThreadPoolMonitor.init(); } public static void initLogger() throws JoranException { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java deleted file mode 100644 index 2632d4340f..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ParameterConverter.java +++ /dev/null @@ -1,24 +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.proxy.common; - -import io.grpc.Context; - -@FunctionalInterface -public interface ParameterConverter { - R convert(Context ctx, T parameter) throws Throwable; -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java index 2c9b663a9a..23eb1e1536 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FilterUtils.java @@ -24,7 +24,7 @@ public class FilterUtils { * Whether the message's tag matches consumerGroup's SubscriptionData * * @param tagsSet, tagSet in {@link SubscriptionData}, tagSet empty means SubscriptionData.SUB_ALL(*) - * @param tags, message's tags, null means not tag attached to the message. + * @param tags, message's tags, null means not tag attached to the message. */ public static boolean isTagMatched(Set tagsSet, String tags) { if (tagsSet.isEmpty()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java index 3e3c5623ee..2e194a8cbe 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/FutureUtils.java @@ -22,7 +22,8 @@ import java.util.concurrent.ExecutorService; public class FutureUtils { - public static CompletableFuture appendNextFuture(CompletableFuture future, CompletableFuture nextFuture, ExecutorService executor) { + public static CompletableFuture appendNextFuture(CompletableFuture future, + CompletableFuture nextFuture, ExecutorService executor) { future.whenCompleteAsync((t, throwable) -> { if (throwable != null) { nextFuture.completeExceptionally(throwable); 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 6bf4ecf653..49e7b4ae80 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 @@ -31,6 +31,7 @@ public class ProxyConfig { */ private boolean enablePrintJstack = true; private long printJstackInMillis = Duration.ofSeconds(60).toMillis(); + private long printThreadPoolStatusInMillis = Duration.ofSeconds(3).toMillis(); private String nameSrvAddr = ""; private String nameSrvDomain = ""; @@ -124,6 +125,14 @@ public class ProxyConfig { this.printJstackInMillis = printJstackInMillis; } + public long getPrintThreadPoolStatusInMillis() { + return printThreadPoolStatusInMillis; + } + + public void setPrintThreadPoolStatusInMillis(long printThreadPoolStatusInMillis) { + this.printThreadPoolStatusInMillis = printThreadPoolStatusInMillis; + } + public String getNameSrvAddr() { return nameSrvAddr; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java index 62614b3a5e..c8aa39959e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/InterceptorConstants.java @@ -35,7 +35,6 @@ public class InterceptorConstants { public static final Metadata.Key LOCAL_ADDRESS = Metadata.Key.of("rpc-local-address", Metadata.ASCII_STRING_MARSHALLER); - public static final Metadata.Key AUTHORIZATION = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 50d5f180a0..1422c01e78 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -103,7 +103,8 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme } @Override - public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { + public void receiveMessage(Context ctx, ReceiveMessageRequest request, + StreamObserver responseObserver) { this.receiveMessageActivity.receiveMessage(ctx, request, responseObserver); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java index 68337cba1c..796d5f57af 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java @@ -53,17 +53,21 @@ public interface GrpcMessingActivity extends StartAndShutdown { CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); - void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver); + void receiveMessage(Context ctx, ReceiveMessageRequest request, + StreamObserver responseObserver); CompletableFuture ackMessage(Context ctx, AckMessageRequest request); - CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, ForwardMessageToDeadLetterQueueRequest request); + CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + ForwardMessageToDeadLetterQueueRequest request); CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); - CompletableFuture notifyClientTermination(Context ctx, NotifyClientTerminationRequest request); + CompletableFuture notifyClientTermination(Context ctx, + NotifyClientTerminationRequest request); - CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request); + CompletableFuture changeInvisibleDuration(Context ctx, + ChangeInvisibleDurationRequest request); StreamObserver telemetry(Context ctx, StreamObserver responseObserver); } 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 fd07618c45..d063b6524b 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 @@ -54,7 +54,7 @@ public class GrpcChannelManager implements StartAndShutdown { protected void init() { this.scheduledExecutorService.scheduleAtFixedRate( this::scanExpireResultFuture, - 10, 10, TimeUnit.SECONDS + 10, 10, TimeUnit.SECONDS ); } @@ -77,7 +77,7 @@ public class GrpcChannelManager implements StartAndShutdown { return clientIdChannelMap.get(clientId); } - public GrpcClientChannel removeChannel(String group, String clientId) { + public GrpcClientChannel removeChannel(String group, String clientId) { AtomicReference channelRef = new AtomicReference<>(); this.groupClientIdChannelMap.computeIfPresent(group, (groupKey, clientIdMap) -> { channelRef.set(clientIdMap.remove(clientId)); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 2f25483041..a8492b140f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -50,7 +50,8 @@ public class GrpcClientChannel extends ProxyChannel { private final String group; private final String clientId; - public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, Context ctx, String group, String clientId) { + public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, Context ctx, + String group, String clientId) { super(proxyRelayService, null, new GrpcChannelId(group, clientId), InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS), InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java index b68e1a77f9..412b01d34b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java @@ -62,7 +62,7 @@ public class ResponseBuilder { .setMessage(message) .build(); } - + public static Code buildCode(int remotingResponseCode) { switch (remotingResponseCode) { case ResponseCode.SUCCESS: diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java index d411184149..3f9f2b2174 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/PopMessageResultFilterImpl.java @@ -32,7 +32,8 @@ public class PopMessageResultFilterImpl implements PopMessageResultFilter { } @Override - public FilterResult filterMessage(ProxyContext ctx, String consumerGroup, SubscriptionData subscriptionData, MessageExt messageExt) { + public FilterResult filterMessage(ProxyContext ctx, String consumerGroup, SubscriptionData subscriptionData, + MessageExt messageExt) { int maxAttempts = grpcClientSettingsManager.getClientSettings(ctx).getBackoffPolicy().getMaxAttempts(); if (!FilterUtils.isTagMatched(subscriptionData.getTagsSet(), messageExt.getTags())) { return FilterResult.NO_MATCH; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 0bd8bf565a..3c8b045a07 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -111,7 +111,8 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { } } - protected ReceiveMessageResponseStreamWriter createWriter(ProxyContext ctx, StreamObserver responseObserver) { + protected ReceiveMessageResponseStreamWriter createWriter(ProxyContext ctx, + StreamObserver responseObserver) { return new ReceiveMessageResponseStreamWriter( this.messagingProcessor, responseObserver 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 1932c3f83b..07d28f8e46 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 @@ -57,7 +57,7 @@ public interface MessagingProcessor extends StartAndShutdown { ProxyContext ctx, List

requestHostAndPortList, String topicName - ) throws Exception; + ) throws Exception; default CompletableFuture> sendMessage( ProxyContext ctx, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java index 43eae1e314..137be90956 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/TopicMessageTypeValidator.java @@ -22,8 +22,9 @@ import org.apache.rocketmq.common.attribute.TopicMessageType; public interface TopicMessageTypeValidator { /** * Will throw {@link org.apache.rocketmq.proxy.common.ProxyException} if validate failed. + * * @param topicMessageType Target topic - * @param messageType Message's type + * @param messageType Message's type */ void validate(TopicMessageType topicMessageType, TopicMessageType messageType); } 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 cd37acaf09..45a8d7cec6 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 @@ -37,10 +37,10 @@ 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.proxy.service.mqclient.DoNothingClientRemotingProcessor; +import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.mqclient.ProxyClientRemotingProcessor; import org.apache.rocketmq.proxy.service.relay.ClusterProxyRelayService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; -import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.ClusterTopicRouteService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.ClusterTransactionService; 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 42c9e249d2..c69b6773a0 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 @@ -115,11 +115,13 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser } private class LocalServiceManagerStartAndShutdown implements StartAndShutdown { - @Override public void start() throws Exception { + @Override + public void start() throws Exception { LocalServiceManager.this.scheduledExecutorService.scheduleWithFixedDelay(channelManager::scanAndCleanChannels, 5, 5, TimeUnit.MINUTES); } - @Override public void shutdown() throws Exception { + @Override + public void shutdown() throws Exception { LocalServiceManager.this.scheduledExecutorService.shutdown(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java index 6a4f1cf371..563b567152 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/ServiceManager.java @@ -20,8 +20,8 @@ import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.message.MessageService; -import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.metadata.MetadataService; +import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionService; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java index 9f010526b8..4b700c5ed7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java @@ -36,6 +36,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; /** * SimpleChannel is used to handle writeAndFlush situation in processor + * * @see io.netty.channel.ChannelHandlerContext#writeAndFlush * @see io.netty.channel.Channel#writeAndFlush */ @@ -51,9 +52,9 @@ public class SimpleChannel extends AbstractChannel { /** * Creates a new instance. * - * @param parent the parent of this channel. {@code null} if there's no parent. - * @param remoteAddress Remote address - * @param localAddress Local address + * @param parent the parent of this channel. {@code null} if there's no parent. + * @param remoteAddress Remote address + * @param localAddress Local address */ public SimpleChannel(Channel parent, String remoteAddress, String localAddress) { super(parent); 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 4fc8fdad9e..3238c69ba1 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 @@ -59,12 +59,12 @@ public class ClusterMessageService implements MessageService { future = this.mqClientAPIFactory.getClient().sendMessageAsync( messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), msgList.get(0), requestHeader, timeoutMillis) - .thenApply(Lists::newArrayList); + .thenApply(Lists::newArrayList); } else { future = this.mqClientAPIFactory.getClient().sendMessageAsync( messageQueue.getBrokerAddr(), messageQueue.getBrokerName(), msgList, requestHeader, timeoutMillis) - .thenApply(Lists::newArrayList); + .thenApply(Lists::newArrayList); } return future; } @@ -81,7 +81,8 @@ public class ClusterMessageService implements MessageService { @Override public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, - EndTransactionRequestHeader requestHeader, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + EndTransactionRequestHeader requestHeader, + long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { this.mqClientAPIFactory.getClient().endTransactionOneway( this.resolveBrokerAddr(transactionId.getBrokerName()), requestHeader, 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 4e893c384f..1c079d7fb3 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 @@ -75,7 +75,8 @@ public class LocalMessageService implements MessageService { this.channelManager = channelManager; } - @Override public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + @Override + public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { byte[] body; String messageId; @@ -162,7 +163,8 @@ public class LocalMessageService implements MessageService { return future; } - @Override public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, + @Override + public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, EndTransactionRequestHeader requestHeader, long timeoutMillis) { SimpleChannel channel = channelManager.createChannel(ctx); ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); @@ -175,7 +177,8 @@ public class LocalMessageService implements MessageService { } } - @Override public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + @Override + public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis) { RemotingCommand request = LocalRemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); CompletableFuture future = new CompletableFuture<>(); @@ -315,7 +318,8 @@ public class LocalMessageService implements MessageService { }); } - @Override public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, + @Override + public CompletableFuture ackMessage(ProxyContext ctx, ReceiptHandle handle, String messageId, AckMessageRequestHeader requestHeader, long timeoutMillis) { SimpleChannel channel = channelManager.createChannel(ctx); ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 011500f8a2..1af6f3acb7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -431,7 +431,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public CompletableFuture searchOffsetAsync(String brokerAddr, String topic, int queueId , long timestamp, long timeoutMillis) { + public CompletableFuture searchOffsetAsync(String brokerAddr, String topic, int queueId, long timestamp, + long timeoutMillis) { SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); requestHeader.setTopic(topic); requestHeader.setQueueId(queueId); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java index ca3edf3ef7..d932cd1596 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java @@ -46,7 +46,8 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { } @Override - public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { + public RemotingCommand checkTransactionState(ChannelHandlerContext ctx, + RemotingCommand request) throws RemotingCommandException { final ByteBuffer byteBuffer = ByteBuffer.wrap(request.getBody()); final MessageExt messageExt = MessageDecoder.decode(byteBuffer, true, false, false); if (messageExt != null) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java index 9b356e788b..fd7afaec9a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java @@ -36,7 +36,8 @@ public class ClusterProxyRelayService implements ProxyRelayService { return null; } - @Override public CompletableFuture> processConsumeMessageDirectly( + @Override + public CompletableFuture> processConsumeMessageDirectly( ProxyContext context, RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header) { return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 54bf8d0a7d..12a6ae6541 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -56,7 +56,8 @@ public abstract class ProxyChannel extends AbstractChannel { protected final ProxyRelayService proxyRelayService; - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, String localAddress) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, + String localAddress) { super(parent); this.proxyRelayService = proxyRelayService; this.remoteAddress = remoteAddress; @@ -65,7 +66,8 @@ public abstract class ProxyChannel extends AbstractChannel { this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, String localAddress) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, + String localAddress) { super(parent, id); this.proxyRelayService = proxyRelayService; this.remoteAddress = remoteAddress; 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 5da75cea08..0c83da60c2 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 @@ -56,7 +56,8 @@ public class LocalTopicRouteService extends TopicRouteService { } @Override - public ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, String topicName) throws Exception { + public ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, + String topicName) throws Exception { MessageQueueView messageQueueView = getAllMessageQueueView(topicName); TopicRouteData topicRouteData = messageQueueView.getTopicRouteData(); 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 7c2f40a6e0..02c817f6f3 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 @@ -193,7 +193,8 @@ public class MessageQueueSelector { return Objects.hash(queues, brokerActingQueues); } - @Override public String toString() { + @Override + public String toString() { return MoreObjects.toStringHelper(this) .add("queues", queues) .add("brokerActingQueues", brokerActingQueues) 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 06c9d14569..cdef39cc2d 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 @@ -53,7 +53,8 @@ public class MessageQueueView { return writeSelector; } - @Override public String toString() { + @Override + public String toString() { return MoreObjects.toStringHelper(this) .add("readSelector", readSelector) .add("writeSelector", writeSelector) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java index 85f7434aed..99eccbedfc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java @@ -72,7 +72,8 @@ public class SelectableMessageQueue implements Comparable requestHostAndPortList, String topicName) throws Exception; + public abstract ProxyTopicRouteData getTopicRouteForProxy(List
requestHostAndPortList, + String topicName) throws Exception; public abstract String getBrokerAddr(String brokerName) throws Exception; - protected static MessageQueueView getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { + protected static MessageQueueView getCacheMessageQueueWrapper(LoadingCache topicCache, + String key) throws Exception { MessageQueueView res = topicCache.get(key); if (res.isEmptyCachedQueue()) { throw new MQClientException(ResponseCode.TOPIC_NOT_EXIST, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index 210f092203..93966d4f79 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -57,7 +57,8 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS private final Map/* cluster list */> groupClusterData = new ConcurrentHashMap<>(); private TxHeartbeatServiceThread txHeartbeatServiceThread; - public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, RPCHook rpcHook, + public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, + RPCHook rpcHook, MQClientAPIFactory mqClientAPIFactory) { this.topicRouteService = topicRouteService; this.mqClientAPIFactory = mqClientAPIFactory; @@ -186,7 +187,7 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData) { try { - MessageQueueView messageQueue = this.topicRouteService.getAllMessageQueueView(clusterName); + MessageQueueView messageQueue = this.topicRouteService.getAllMessageQueueView(clusterName); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); if (brokerDataList == null) { return; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java index c465520a98..fe0a1c0451 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java @@ -18,20 +18,27 @@ package org.apache.rocketmq.proxy.service.transaction; import java.util.List; +/** + * no need to implements, because the channel of producer will put into the broker's producerManager + */ public class LocalTransactionService implements TransactionService { - @Override public void addTransactionSubscription(String group, List topicList) { + @Override + public void addTransactionSubscription(String group, List topicList) { } - @Override public void addTransactionSubscription(String group, String topic) { + @Override + public void addTransactionSubscription(String group, String topic) { } - @Override public void replaceTransactionSubscription(String group, List topicList) { + @Override + public void replaceTransactionSubscription(String group, List topicList) { } - @Override public void unSubscribeAllTransactionTopic(String group) { + @Override + public void unSubscribeAllTransactionTopic(String group) { } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java index 44b5056911..78b479634a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java @@ -181,7 +181,8 @@ public class TransactionId { this.proxyTransactionId = proxyTransactionId; } - @Override public String toString() { + @Override + public String toString() { return MoreObjects.toStringHelper(this) .add("brokerName", brokerName) .add("brokerTransactionId", brokerTransactionId) @@ -230,7 +231,8 @@ public class TransactionId { return new TransactionId(brokerName, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); } - @Override public String toString() { + @Override + public String toString() { return MoreObjects.toStringHelper(this) .add("brokerName", brokerName) .add("brokerTransactionId", brokerTransactionId) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index c17cca7c2c..bb28e43aea 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -31,7 +31,6 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.junit.Ignore; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import static org.mockito.Mockito.mock; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 5fc223787c..79999164f4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -48,7 +48,7 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { GrpcMessagingApplication grpcMessagingApplication; private static final String TOPIC = "topic"; - private static Endpoints GRPC_ENDPOINTS = Endpoints.newBuilder() + private static Endpoints grpcEndpoints = Endpoints.newBuilder() .setScheme(AddressScheme.IPv4) .addAddresses(Address.newBuilder().setHost("127.0.0.1").setPort(8080).build()) .addAddresses(Address.newBuilder().setHost("127.0.0.2").setPort(8080).build()) @@ -64,7 +64,7 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { public void testQueryRoute() { CompletableFuture future = new CompletableFuture<>(); QueryRouteRequest request = QueryRouteRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(Resource.newBuilder().setName(TOPIC).build()) .build(); Mockito.when(grpcMessingActivity.queryRoute(Mockito.any(Context.class), Mockito.eq(request))) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index b295cbb477..242d62ee5a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -261,13 +261,16 @@ public class ClientActivityTest extends BaseActivityTest { when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) runningInfoFutureMock); Context context = createContext(); StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { - @Override public void onNext(TelemetryCommand value) { + @Override + public void onNext(TelemetryCommand value) { } - @Override public void onError(Throwable t) { + @Override + public void onError(Throwable t) { } - @Override public void onCompleted() { + @Override + public void onCompleted() { } }); streamObserver.onNext(TelemetryCommand.newBuilder() @@ -290,13 +293,16 @@ public class ClientActivityTest extends BaseActivityTest { when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) resultFutureMock); Context context = createContext(); StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { - @Override public void onNext(TelemetryCommand value) { + @Override + public void onNext(TelemetryCommand value) { } - @Override public void onError(Throwable t) { + @Override + public void onError(Throwable t) { } - @Override public void onCompleted() { + @Override + public void onCompleted() { } }); streamObserver.onNext(TelemetryCommand.newBuilder() @@ -326,7 +332,8 @@ public class ClientActivityTest extends BaseActivityTest { } - @Override public void onCompleted() { + @Override + public void onCompleted() { } }; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java index bf89caab64..28a422df0f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java @@ -67,7 +67,7 @@ public class GrpcClientSettingsManagerTest extends BaseActivityTest { subscriptionGroupConfig.setRetryMaxTimes(3); subscriptionGroupConfig.getGroupRetryPolicy().setType(GroupRetryPolicyType.CUSTOMIZED); - subscriptionGroupConfig.getGroupRetryPolicy().setCustomizedRetryPolicy(new CustomizedRetryPolicy(new long[]{1000})); + subscriptionGroupConfig.getGroupRetryPolicy().setCustomizedRetryPolicy(new CustomizedRetryPolicy(new long[] {1000})); settings = this.grpcClientSettingsManager.getClientSettings(context); assertEquals(RetryPolicy.newBuilder() .setMaxAttempts(3) 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 6ca311d6ff..d4a34cbb0c 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 @@ -24,14 +24,13 @@ import apache.rocketmq.v2.Code; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; -import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java index cf1c8b7983..4d6655530f 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java @@ -31,7 +31,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; 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 412e5806c9..40a5ed4243 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 @@ -42,7 +42,6 @@ import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; -import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java index c6153d7133..1bae776f9c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java @@ -29,7 +29,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index ebb821fd3b..583dbc995e 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -58,18 +58,18 @@ public class RouteActivityTest extends BaseActivityTest { private static final Resource GRPC_TOPIC = Resource.newBuilder() .setName(TOPIC) .build(); - private static Endpoints GRPC_ENDPOINTS = Endpoints.newBuilder() + private static Endpoints grpcEndpoints = Endpoints.newBuilder() .setScheme(AddressScheme.IPv4) .addAddresses(Address.newBuilder().setHost("127.0.0.1").setPort(8080).build()) .addAddresses(Address.newBuilder().setHost("127.0.0.2").setPort(8080).build()) .build(); - private static List ENDPOINTS_ADDRESS = new ArrayList<>(); + private static List addressArrayList = new ArrayList<>(); static { - ENDPOINTS_ADDRESS.add(new org.apache.rocketmq.proxy.common.Address( + addressArrayList.add(new org.apache.rocketmq.proxy.common.Address( org.apache.rocketmq.proxy.common.Address.AddressScheme.IPv4, HostAndPort.fromParts("127.0.0.1", 8080))); - ENDPOINTS_ADDRESS.add(new org.apache.rocketmq.proxy.common.Address( + addressArrayList.add(new org.apache.rocketmq.proxy.common.Address( org.apache.rocketmq.proxy.common.Address.AddressScheme.IPv4, HostAndPort.fromParts("127.0.0.2", 8080))); } @@ -89,16 +89,16 @@ public class RouteActivityTest extends BaseActivityTest { QueryRouteResponse response = this.routeActivity.queryRoute( createContext(), QueryRouteRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(Resource.newBuilder().setName(TOPIC).build()) .build() ).get(); - assertEquals(ENDPOINTS_ADDRESS, addressListCaptor.getValue()); + assertEquals(addressArrayList, addressListCaptor.getValue()); assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(4, response.getMessageQueuesCount()); for (MessageQueue messageQueue : response.getMessageQueuesList()) { - assertEquals(GRPC_ENDPOINTS, messageQueue.getBroker().getEndpoints()); + assertEquals(grpcEndpoints, messageQueue.getBroker().getEndpoints()); assertEquals(Permission.READ_WRITE, messageQueue.getPermission()); } } @@ -111,7 +111,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryRouteResponse response = this.routeActivity.queryRoute( createContext(), QueryRouteRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) .build() ).get(); @@ -127,7 +127,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentResponse response = this.routeActivity.queryAssignment( createContext(), QueryAssignmentRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) .build() ).get(); @@ -143,7 +143,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentResponse response = this.routeActivity.queryAssignment( createContext(), QueryAssignmentRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) .build() ).get(); @@ -159,14 +159,14 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentResponse response = this.routeActivity.queryAssignment( createContext(), QueryAssignmentRequest.newBuilder() - .setEndpoints(GRPC_ENDPOINTS) + .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) .build() ).get(); assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(1, response.getAssignmentsCount()); - assertEquals(GRPC_ENDPOINTS, response.getAssignments(0).getMessageQueue().getBroker().getEndpoints()); + assertEquals(grpcEndpoints, response.getAssignments(0).getMessageQueue().getBroker().getEndpoints()); } private static ProxyTopicRouteData createProxyTopicRouteData(int r, int w, int p) { @@ -175,8 +175,8 @@ public class RouteActivityTest extends BaseActivityTest { ProxyTopicRouteData.ProxyBrokerData proxyBrokerData = new ProxyTopicRouteData.ProxyBrokerData(); proxyBrokerData.setCluster(CLUSTER); proxyBrokerData.setBrokerName(BROKER_NAME); - proxyBrokerData.getBrokerAddrs().put(0L, ENDPOINTS_ADDRESS); - proxyBrokerData.getBrokerAddrs().put(1L, ENDPOINTS_ADDRESS); + proxyBrokerData.getBrokerAddrs().put(0L, addressArrayList); + proxyBrokerData.getBrokerAddrs().put(1L, addressArrayList); proxyTopicRouteData.getBrokerDatas().add(proxyBrokerData); return proxyTopicRouteData; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java index 6709ae05ff..a2444a6e88 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java @@ -91,7 +91,7 @@ public class EndTransactionActivityTest extends BaseActivityTest { @Parameterized.Parameters public static Collection parameters() { - Object[][] p = new Object[][]{ + Object[][] p = new Object[][] { {TransactionResolution.COMMIT, TransactionSource.SOURCE_CLIENT, TransactionStatus.COMMIT, false}, {TransactionResolution.ROLLBACK, TransactionSource.SOURCE_SERVER_CHECK, TransactionStatus.ROLLBACK, true}, {TransactionResolution.TRANSACTION_RESOLUTION_UNSPECIFIED, TransactionSource.SOURCE_SERVER_CHECK, TransactionStatus.UNKNOWN, true}, 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 dbac6b4e99..35ab32a9e9 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 @@ -58,7 +58,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { private static final String CONSUMER_GROUP = "consumerGroup"; private static final String TOPIC = "topic"; - + private ConsumerProcessor consumerProcessor; @Before diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 7208c6da83..5b66fa8ed0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -77,7 +77,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { sendResult.setMsgId(msgId); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) - .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); + .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); List messageExtList = new ArrayList<>(); MessageExt messageExt = createMessageExt(TOPIC, "tag", 0, 0); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java index 7eeb72060e..2c0d3f8909 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/metadata/ClusterMetadataServiceTest.java @@ -18,14 +18,11 @@ package org.apache.rocketmq.proxy.service.metadata; import java.util.HashMap; -import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.attribute.TopicMessageType; -import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.service.BaseServiceTest; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.junit.Before; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java index b78502e2c1..db3ef7bf8d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java @@ -313,7 +313,6 @@ public class MQClientAPIExtTest { assertEquals(offset, mqClientAPI.getMaxOffsetAsync(BROKER_ADDR, TOPIC, 0, TIMEOUT).get().longValue()); } - @Test public void testSearchOffsetAsync() throws Exception { long offset = ThreadLocalRandom.current().nextLong(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java index a6d6d60f14..fadb280e37 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.proxy.service.relay; import io.netty.channel.Channel; -import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -40,7 +39,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -57,11 +58,13 @@ public class ProxyChannelTest { super(proxyRelayService, parent, remoteAddress, localAddress); } - @Override public boolean isOpen() { + @Override + public boolean isOpen() { return false; } - @Override public boolean isActive() { + @Override + public boolean isActive() { return false; } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java index 2d5f64de37..2a5d3189eb 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/ClusterTopicRouteServiceTest.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.proxy.service.route; import com.google.common.net.HostAndPort; -import java.util.ArrayList; import java.util.List; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; @@ -30,7 +29,9 @@ import org.junit.Before; import org.junit.Test; import static org.assertj.core.api.Assertions.catchThrowableOfType; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java index 72fad8f13a..c9b3b17657 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java @@ -30,10 +30,8 @@ import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; @@ -43,7 +41,6 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; - public class ClusterTransactionServiceTest extends BaseServiceTest { @Mock diff --git a/proxy/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml b/proxy/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml index 8d0458ebf0..74829684e8 100644 --- a/proxy/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml +++ b/proxy/src/test/resources/rmq-proxy-home/conf/logback_proxy.xml @@ -25,7 +25,7 @@ ${user.home}/logs/rocketmqlogs/otherdays/proxy.%i.log.gz 1 - 20 + 10 128MB @@ -39,25 +39,25 @@ - - ${user.home}/logs/rocketmqlogs/grpc.log + ${user.home}/logs/rocketmqlogs/proxy_watermark.log true - ${user.home}/logs/rocketmqlogs/otherdays/grpc.%i.log.gz + ${user.home}/logs/rocketmqlogs/otherdays/proxy_watermark.%i.log.gz 1 - 20 + 10 128MB - %d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n + %d{yyy-MM-dd HH:mm:ss,GMT+8}%m%n UTF-8 - - + + @@ -312,7 +312,7 @@ 20 + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> 128MB @@ -408,9 +408,9 @@ - + - + From e52efc4ac6fc3a031028106487fbcb1ec8639f6c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 2 Jun 2022 11:15:25 +0800 Subject: [PATCH 237/338] [ISSUE #3949] not decompress body in proxy --- .../apache/rocketmq/client/ClientConfig.java | 27 ++++++++- .../rocketmq/client/impl/MQClientAPIImpl.java | 6 +- .../client/impl/consumer/PullAPIWrapper.java | 7 ++- .../service/mqclient/MQClientAPIFactory.java | 2 + .../rocketmq/test/grpc/v2/ClusterGrpcIT.java | 8 ++- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 55 +++++++++++++++++-- .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 7 ++- 7 files changed, 102 insertions(+), 10 deletions(-) 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 4452bbdfa1..b5ba1cbceb 100644 --- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java @@ -34,6 +34,8 @@ import org.apache.rocketmq.remoting.protocol.LanguageCode; */ public class ClientConfig { public static final String SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY = "com.rocketmq.sendMessageWithVIPChannel"; + public static final String DECODE_READ_BODY = "com.rocketmq.read.body"; + public static final String DECODE_DECOMPRESS_BODY = "com.rocketmq.decompress.body"; private String namesrvAddr = NameServerAddressUtils.getNameServerAddresses(); private String clientIP = RemotingUtil.getLocalAddress(); private String instanceName = System.getProperty("rocketmq.client.name", "DEFAULT"); @@ -57,6 +59,8 @@ public class ClientConfig { private long pullTimeDelayMillsWhenException = 1000; private boolean unitMode = false; private String unitName; + private boolean decodeReadBody = Boolean.parseBoolean(System.getProperty(DECODE_READ_BODY, "true")); + private boolean decodeDecompressBody = Boolean.parseBoolean(System.getProperty(DECODE_DECOMPRESS_BODY, "true")); private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false")); private boolean useTLS = TlsSystemConfig.tlsEnable; @@ -160,6 +164,8 @@ public class ClientConfig { this.namespace = cc.namespace; this.language = cc.language; this.mqClientApiTimeout = cc.mqClientApiTimeout; + this.decodeReadBody = cc.decodeReadBody; + this.decodeDecompressBody = cc.decodeDecompressBody; } public ClientConfig cloneClientConfig() { @@ -179,6 +185,8 @@ public class ClientConfig { cc.namespace = namespace; cc.language = language; cc.mqClientApiTimeout = mqClientApiTimeout; + cc.decodeReadBody = decodeReadBody; + cc.decodeDecompressBody = decodeDecompressBody; return cc; } @@ -279,6 +287,22 @@ public class ClientConfig { this.language = language; } + public boolean isDecodeReadBody() { + return decodeReadBody; + } + + public void setDecodeReadBody(boolean decodeReadBody) { + this.decodeReadBody = decodeReadBody; + } + + public boolean isDecodeDecompressBody() { + return decodeDecompressBody; + } + + public void setDecodeDecompressBody(boolean decodeDecompressBody) { + this.decodeDecompressBody = decodeDecompressBody; + } + public String getNamespace() { if (namespaceInitialized) { return namespace; @@ -324,6 +348,7 @@ public class ClientConfig { + ", clientCallbackExecutorThreads=" + clientCallbackExecutorThreads + ", pollNameServerInterval=" + pollNameServerInterval + ", heartbeatBrokerInterval=" + heartbeatBrokerInterval + ", persistConsumerOffsetInterval=" + persistConsumerOffsetInterval + ", pullTimeDelayMillsWhenException=" + pullTimeDelayMillsWhenException + ", unitMode=" + unitMode + ", unitName=" + unitName + ", vipChannelEnabled=" - + vipChannelEnabled + ", useTLS=" + useTLS + ", language=" + language.name() + ", namespace=" + namespace + ", mqClientApiTimeout=" + mqClientApiTimeout + "]"; + + vipChannelEnabled + ", useTLS=" + useTLS + ", language=" + language.name() + ", namespace=" + namespace + ", mqClientApiTimeout=" + mqClientApiTimeout + + ", decodeReadBody=" + decodeReadBody + ", decodeDecompressBody=" + decodeDecompressBody + "]"; } } 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 765184478f..c7d2f848c7 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 @@ -1034,7 +1034,11 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { case ResponseCode.SUCCESS: popStatus = PopStatus.FOUND; ByteBuffer byteBuffer = ByteBuffer.wrap(response.getBody()); - msgFoundList = MessageDecoder.decodes(byteBuffer); + msgFoundList = MessageDecoder.decodesBatch( + byteBuffer, + clientConfig.isDecodeReadBody(), + clientConfig.isDecodeDecompressBody(), + true); break; case ResponseCode.POLLING_FULL: popStatus = PopStatus.POLLING_FULL; diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java index 6ce8e261ca..9b0fa8df77 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java @@ -78,7 +78,12 @@ public class PullAPIWrapper { this.updatePullFromWhichNode(mq, pullResultExt.getSuggestWhichBrokerId()); if (PullStatus.FOUND == pullResult.getPullStatus()) { ByteBuffer byteBuffer = ByteBuffer.wrap(pullResultExt.getMessageBinary()); - List msgList = MessageDecoder.decodes(byteBuffer); + List msgList = MessageDecoder.decodesBatch( + byteBuffer, + this.mQClientFactory.getClientConfig().isDecodeReadBody(), + this.mQClientFactory.getClientConfig().isDecodeDecompressBody(), + true + ); boolean needDecodeInnerMessage = false; for (MessageExt messageExt: msgList) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java index abdfa5404a..0b813ae608 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIFactory.java @@ -89,6 +89,8 @@ public class MQClientAPIFactory implements StartAndShutdown { protected MQClientAPIExt createAndStart(String instanceName) { ClientConfig clientConfig = new ClientConfig(); clientConfig.setInstanceName(instanceName); + clientConfig.setDecodeReadBody(true); + clientConfig.setDecodeDecompressBody(false); NettyClientConfig nettyClientConfig = new NettyClientConfig(); nettyClientConfig.setDisableCallbackExecutor(true); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index 8fcd9f3323..fa0a6ca7e8 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -69,7 +69,7 @@ public class ClusterGrpcIT extends GrpcBaseIT { String topic = initTopic(); QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); - assertQueryRoute(response, brokerNum * defaultQueueNums); + assertQueryRoute(response, brokerNum * DEFAULT_QUEUE_NUMS); } @Test @@ -87,6 +87,12 @@ public class ClusterGrpcIT extends GrpcBaseIT { super.testTransactionCheckThenCommit(); } + + @Test + public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { + super.testSimpleConsumerSendAndRecvBigMessage(); + } + @Test public void testSimpleConsumerSendAndRecv() throws Exception { super.testSimpleConsumerSendAndRecv(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index f1f79bfcdf..85ae8f1faf 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -27,6 +27,7 @@ import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Encoding; import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.Endpoints; @@ -101,6 +102,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.test.base.BaseConf; import org.apache.rocketmq.test.util.MQRandomUtils; +import org.apache.rocketmq.test.util.RandomUtils; import org.junit.Rule; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; @@ -110,7 +112,7 @@ import static org.awaitility.Awaitility.await; public class GrpcBaseIT extends BaseConf { - protected final int PORT = 8082; + protected final int port = 8082; /** * This rule manages automatic graceful shutdown for the registered servers and channels at the end of test. */ @@ -121,7 +123,7 @@ public class GrpcBaseIT extends BaseConf { protected MessagingServiceGrpc.MessagingServiceStub stub; protected final Metadata header = new Metadata(); - protected static final int defaultQueueNums = 8; + protected static final int DEFAULT_QUEUE_NUMS = 8; public void setUp() throws Exception { brokerController1.getBrokerConfig().setTransactionCheckInterval(3 * 1000); @@ -139,7 +141,7 @@ public class GrpcBaseIT extends BaseConf { System.setProperty(RMQ_PROXY_HOME, mockProxyHome); ConfigurationManager.initEnv(); ConfigurationManager.intConfig(); - ConfigurationManager.getProxyConfig().setGrpcServerPort(PORT); + ConfigurationManager.getProxyConfig().setGrpcServerPort(port); ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); // Set LongPollingReserveTimeInMillis to 500ms to reserve more time for IT ConfigurationManager.getProxyConfig().setLongPollingReserveTimeInMillis(500); @@ -303,6 +305,30 @@ public class GrpcBaseIT extends BaseConf { .build(); } + public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name); + String group = MQRandomUtils.getRandomConsumerGroup(); + + int maxDeliveryAttempts = 16; + boolean fifo = false; + int bodySize = 4 * 1024; + + // init consumer offset + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + receiveMessage(blockingStub, topic, group, 1); + + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendBigMessageRequest(topic, messageId, bodySize)); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + + Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); + assertThat(message.getSystemProperties().getBodyEncoding()).isEqualTo(Encoding.GZIP); + assertThat(message.getBody().size()).isEqualTo(bodySize); + } + public void testSimpleConsumerSendAndRecv() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); @@ -432,7 +458,7 @@ public class GrpcBaseIT extends BaseConf { public QueryRouteRequest buildQueryRouteRequest(String topic) { return QueryRouteRequest.newBuilder() - .setEndpoints(buildEndpoints(PORT)) + .setEndpoints(buildEndpoints(port)) .setTopic(Resource.newBuilder() .setName(topic) .build()) @@ -441,7 +467,7 @@ public class GrpcBaseIT extends BaseConf { public QueryAssignmentRequest buildQueryAssignmentRequest(String topic, String group) { return QueryAssignmentRequest.newBuilder() - .setEndpoints(buildEndpoints(PORT)) + .setEndpoints(buildEndpoints(port)) .setTopic(Resource.newBuilder().setName(topic).build()) .setGroup(Resource.newBuilder().setName(group).build()) .build(); @@ -465,6 +491,25 @@ public class GrpcBaseIT extends BaseConf { .build(); } + public SendMessageRequest buildSendBigMessageRequest(String topic, String messageId, int messageSize) { + return SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(messageId) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBodyEncoding(Encoding.GZIP) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8(RandomUtils.getStringWithCharacter(messageSize))) + .build()) + .build(); + } + public SendMessageRequest buildTransactionSendMessageRequest(String topic, String messageId) { return SendMessageRequest.newBuilder() .addMessages(Message.newBuilder() diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 5aa188329e..fc113370bc 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -57,7 +57,7 @@ public class LocalGrpcIT extends GrpcBaseIT { String topic = initTopic(); QueryRouteResponse response = blockingStub.queryRoute(buildQueryRouteRequest(topic)); - assertQueryRoute(response, brokerControllerList.size() * defaultQueueNums); + assertQueryRoute(response, brokerControllerList.size() * DEFAULT_QUEUE_NUMS); } @Test @@ -75,6 +75,11 @@ public class LocalGrpcIT extends GrpcBaseIT { super.testTransactionCheckThenCommit(); } + @Test + public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { + super.testSimpleConsumerSendAndRecvBigMessage(); + } + @Test public void testSimpleConsumerSendAndRecv() throws Exception { super.testSimpleConsumerSendAndRecv(); From 64b58a54bbffb450a002afa20adf69819fa50a5f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 2 Jun 2022 11:17:39 +0800 Subject: [PATCH 238/338] support disableNettyWorkerGroup in NettyClientConfig --- .../remoting/netty/NettyRemotingClient.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java index 0cd220215b..cf02d3d66d 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java @@ -210,14 +210,12 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti LOGGER.warn("Connections are insecure as SSLContext is null!"); } } - if (nettyClientConfig.isDefaultEventExecutorGroupEnable() && !nettyClientConfig.isDisableNettyWorkerGroup()) { - ch.pipeline().addLast(defaultEventExecutorGroup); - } - ch.pipeline().addLast(// - new NettyEncoder(), // - new NettyDecoder(), // - new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()), // - new NettyConnectManageHandler(), // + ch.pipeline().addLast( + nettyClientConfig.isDisableNettyWorkerGroup() ? null : defaultEventExecutorGroup, + new NettyEncoder(), + new NettyDecoder(), + new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()), + new NettyConnectManageHandler(), new NettyClientHandler()); } }); From 689c1f39299fa6bae8f4ee422c69f91121639124 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 7 Jun 2022 11:44:11 +0800 Subject: [PATCH 239/338] [ISSUE #3949] Refector send process --- .../AbstractSendMessageProcessor.java | 114 ++---------------- .../AbstractSendMessageProcessorTest.java | 4 +- .../header/SendMessageRequestHeader.java | 95 +++++++++++++++ .../proxy/common/ProxyExceptionCode.java | 1 + .../grpc/v2/producer/SendMessageActivity.java | 51 ++++---- .../proxy/processor/AbstractProcessor.java | 14 +-- .../processor/DefaultMessagingProcessor.java | 6 +- .../proxy/processor/MessagingProcessor.java | 10 +- .../proxy/processor/ProducerProcessor.java | 24 ++-- .../message/ClusterMessageService.java | 2 +- .../service/message/LocalMessageService.java | 2 +- .../proxy/service/message/MessageService.java | 2 +- .../v2/producer/SendMessageActivityTest.java | 41 ++++--- .../processor/ProducerProcessorTest.java | 17 +-- 14 files changed, 194 insertions(+), 189 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java index 18212397d0..daf77d7696 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java @@ -18,12 +18,10 @@ package org.apache.rocketmq.broker.processor; import io.netty.channel.ChannelHandlerContext; import java.net.SocketAddress; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; - import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.mqtrace.AbortProcessException; import org.apache.rocketmq.broker.mqtrace.ConsumeMessageContext; @@ -32,15 +30,10 @@ import org.apache.rocketmq.broker.mqtrace.SendMessageContext; import org.apache.rocketmq.broker.mqtrace.SendMessageHook; import org.apache.rocketmq.common.BrokerConfig; import org.apache.rocketmq.common.MQVersion; -import org.apache.rocketmq.common.UtilAll; -import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageType; -import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; -import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; -import org.apache.rocketmq.common.topic.TopicValidator; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.TopicFilterType; +import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.common.constant.DBMsgConstants; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.constant.PermName; @@ -48,21 +41,24 @@ import org.apache.rocketmq.common.help.FAQUrl; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageExtBrokerInner; +import org.apache.rocketmq.common.message.MessageType; import org.apache.rocketmq.common.protocol.NamespaceUtil; -import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; -import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.sysflag.TopicSysFlag; +import org.apache.rocketmq.common.topic.TopicValidator; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyRequestProcessor; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -import org.apache.rocketmq.common.message.MessageExtBrokerInner; import org.apache.rocketmq.store.PutMessageResult; import org.apache.rocketmq.store.stats.BrokerStatsManager; @@ -574,100 +570,8 @@ public abstract class AbstractSendMessageProcessor implements NettyRequestProces } } - protected SendMessageRequestHeader parseRequestHeader(RemotingCommand request) - throws RemotingCommandException { - - SendMessageRequestHeaderV2 requestHeaderV2 = null; - SendMessageRequestHeader requestHeader = null; - switch (request.getCode()) { - case RequestCode.SEND_BATCH_MESSAGE: - case RequestCode.SEND_MESSAGE_V2: - requestHeaderV2 = decodeSendMessageHeaderV2(request); - case RequestCode.SEND_MESSAGE: - if (null == requestHeaderV2) { - requestHeader = - (SendMessageRequestHeader) request - .decodeCommandCustomHeader(SendMessageRequestHeader.class); - } else { - requestHeader = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV1(requestHeaderV2); - } - default: - break; - } - return requestHeader; - } - - static SendMessageRequestHeaderV2 decodeSendMessageHeaderV2(RemotingCommand request) - throws RemotingCommandException { - SendMessageRequestHeaderV2 r = new SendMessageRequestHeaderV2(); - HashMap fields = request.getExtFields(); - if (fields == null) { - throw new RemotingCommandException("the ext fields is null"); - } - - String s = fields.get("a"); - checkNotNull(s, "the custom field is null"); - r.setA(s); - - s = fields.get("b"); - checkNotNull(s, "the custom field is null"); - r.setB(s); - - s = fields.get("c"); - checkNotNull(s, "the custom field is null"); - r.setC(s); - - s = fields.get("d"); - checkNotNull(s, "the custom field is null"); - r.setD(Integer.parseInt(s)); - - s = fields.get("e"); - checkNotNull(s, "the custom field is null"); - r.setE(Integer.parseInt(s)); - - s = fields.get("f"); - checkNotNull(s, "the custom field is null"); - r.setF(Integer.parseInt(s)); - - s = fields.get("g"); - checkNotNull(s, "the custom field is null"); - r.setG(Long.parseLong(s)); - - s = fields.get("h"); - checkNotNull(s, "the custom field is null"); - r.setH(Integer.parseInt(s)); - - s = fields.get("i"); - if (s != null) { - r.setI(s); - } - - s = fields.get("j"); - if (s != null) { - r.setJ(Integer.parseInt(s)); - } - - s = fields.get("k"); - if (s != null) { - r.setK(Boolean.parseBoolean(s)); - } - - s = fields.get("l"); - if (s != null) { - r.setL(Integer.parseInt(s)); - } - - s = fields.get("m"); - if (s != null) { - r.setM(Boolean.parseBoolean(s)); - } - return r; - } - - private static void checkNotNull(String s, String msg) throws RemotingCommandException { - if (s == null) { - throw new RemotingCommandException(msg); - } + protected SendMessageRequestHeader parseRequestHeader(RemotingCommand request) throws RemotingCommandException { + return SendMessageRequestHeader.parseRequestHeader(request); } protected int randomQueueId(int writeQueueNums) { diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessorTest.java index 01346caaa5..236b2c7061 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessorTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessorTest.java @@ -20,7 +20,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; - +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Assert; @@ -65,7 +65,7 @@ public class AbstractSendMessageProcessorTest { private void check(RemotingCommand command, List fields) throws Exception { SendMessageRequestHeaderV2 o1 = (SendMessageRequestHeaderV2) command.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class); - SendMessageRequestHeaderV2 o2 = AbstractSendMessageProcessor.decodeSendMessageHeaderV2(command); + SendMessageRequestHeaderV2 o2 = SendMessageRequestHeader.decodeSendMessageHeaderV2(command); for (Field f : fields) { Object value1 = f.get(o1); Object value2 = f.get(o2); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java index abea27e502..bae247c99f 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java @@ -21,10 +21,13 @@ package org.apache.rocketmq.common.protocol.header; import com.google.common.base.MoreObjects; +import java.util.HashMap; +import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.rpc.TopicQueueRequestHeader; import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.annotation.CFNullable; import org.apache.rocketmq.remoting.exception.RemotingCommandException; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class SendMessageRequestHeader extends TopicQueueRequestHeader { @CFNotNull @@ -165,6 +168,98 @@ public class SendMessageRequestHeader extends TopicQueueRequestHeader { this.batch = batch; } + public static SendMessageRequestHeader parseRequestHeader(RemotingCommand request) throws RemotingCommandException { + SendMessageRequestHeaderV2 requestHeaderV2 = null; + SendMessageRequestHeader requestHeader = null; + switch (request.getCode()) { + case RequestCode.SEND_BATCH_MESSAGE: + case RequestCode.SEND_MESSAGE_V2: + requestHeaderV2 = decodeSendMessageHeaderV2(request); + case RequestCode.SEND_MESSAGE: + if (null == requestHeaderV2) { + requestHeader = request.decodeCommandCustomHeader(SendMessageRequestHeader.class); + } else { + requestHeader = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV1(requestHeaderV2); + } + default: + break; + } + return requestHeader; + } + + public static SendMessageRequestHeaderV2 decodeSendMessageHeaderV2(RemotingCommand request) + throws RemotingCommandException { + SendMessageRequestHeaderV2 r = new SendMessageRequestHeaderV2(); + HashMap fields = request.getExtFields(); + if (fields == null) { + throw new RemotingCommandException("the ext fields is null"); + } + + String s = fields.get("a"); + checkNotNull(s, "the custom field is null"); + r.setA(s); + + s = fields.get("b"); + checkNotNull(s, "the custom field is null"); + r.setB(s); + + s = fields.get("c"); + checkNotNull(s, "the custom field is null"); + r.setC(s); + + s = fields.get("d"); + checkNotNull(s, "the custom field is null"); + r.setD(Integer.parseInt(s)); + + s = fields.get("e"); + checkNotNull(s, "the custom field is null"); + r.setE(Integer.parseInt(s)); + + s = fields.get("f"); + checkNotNull(s, "the custom field is null"); + r.setF(Integer.parseInt(s)); + + s = fields.get("g"); + checkNotNull(s, "the custom field is null"); + r.setG(Long.parseLong(s)); + + s = fields.get("h"); + checkNotNull(s, "the custom field is null"); + r.setH(Integer.parseInt(s)); + + s = fields.get("i"); + if (s != null) { + r.setI(s); + } + + s = fields.get("j"); + if (s != null) { + r.setJ(Integer.parseInt(s)); + } + + s = fields.get("k"); + if (s != null) { + r.setK(Boolean.parseBoolean(s)); + } + + s = fields.get("l"); + if (s != null) { + r.setL(Integer.parseInt(s)); + } + + s = fields.get("m"); + if (s != null) { + r.setM(Boolean.parseBoolean(s)); + } + return r; + } + + private static void checkNotNull(String s, String msg) throws RemotingCommandException { + if (s == null) { + throw new RemotingCommandException(msg); + } + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 662df1b900..b2a26d9a98 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -24,4 +24,5 @@ public enum ProxyExceptionCode { ILLEGAL_MESSAGE, INTERNAL_SERVER_ERROR, MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, + NOT_IMPLEMENTED, } 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 998c0276fb..50419381c2 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 @@ -18,13 +18,11 @@ package org.apache.rocketmq.proxy.grpc.v2.producer; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Encoding; -import apache.rocketmq.v2.Message; import apache.rocketmq.v2.MessageType; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SendResultEntry; -import apache.rocketmq.v2.SystemProperties; import com.google.common.collect.Maps; import com.google.common.hash.Hashing; import com.google.protobuf.Duration; @@ -40,9 +38,9 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; @@ -71,12 +69,14 @@ public class SendMessageActivity extends AbstractMessingActivity { throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "no message to send"); } - List messageList = request.getMessagesList(); - Resource topic = messageList.get(0).getTopic(); + List messageList = request.getMessagesList(); + apache.rocketmq.v2.Message message = messageList.get(0); + Resource topic = message.getTopic(); future = this.messagingProcessor.sendMessage( context, new SendMessageQueueSelector(request), GrpcConverter.wrapResourceWithNamespace(topic), + buildSysFlag(message), buildMessage(context, request.getMessagesList(), topic) ).thenApply(result -> convertToSendMessageResponse(context, request, result)); } catch (Throwable t) { @@ -85,9 +85,9 @@ public class SendMessageActivity extends AbstractMessingActivity { return future; } - protected List buildMessage(ProxyContext context, List protoMessageList, Resource topic) { + protected List buildMessage(ProxyContext context, List protoMessageList, Resource topic) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); - List messageExtList = new ArrayList<>(); + List messageExtList = new ArrayList<>(); for (apache.rocketmq.v2.Message protoMessage : protoMessageList) { if (!protoMessage.getTopic().equals(topic)) { throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); @@ -98,33 +98,34 @@ public class SendMessageActivity extends AbstractMessingActivity { return messageExtList; } - protected MessageExt buildMessage(Message protoMessage, String producerGroup) { + protected Message buildMessage(apache.rocketmq.v2.Message protoMessage, String producerGroup) { String topicName = GrpcConverter.wrapResourceWithNamespace(protoMessage.getTopic()); - MessageExt messageExt = new MessageExt(); + Message messageExt = new Message(); messageExt.setTopic(topicName); messageExt.setBody(protoMessage.getBody().toByteArray()); Map messageProperty = this.buildMessageProperty(protoMessage, producerGroup); - // sysFlag (body encoding & message type) - SystemProperties systemProperties = protoMessage.getSystemProperties(); - int sysFlag = 0; - Encoding bodyEncoding = systemProperties.getBodyEncoding(); - if (bodyEncoding.equals(Encoding.GZIP)) { - sysFlag |= MessageSysFlag.COMPRESSED_FLAG; - } - // transaction - MessageType messageType = systemProperties.getMessageType(); - if (messageType.equals(MessageType.TRANSACTION)) { - sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; - } - messageExt.setSysFlag(sysFlag); - MessageAccessor.setProperties(messageExt, messageProperty); return messageExt; } - protected Map buildMessageProperty(Message message, String producerGroup) { + protected int buildSysFlag(apache.rocketmq.v2.Message protoMessage) { + // sysFlag (body encoding & message type) + int sysFlag = 0; + Encoding bodyEncoding = protoMessage.getSystemProperties().getBodyEncoding(); + if (bodyEncoding.equals(Encoding.GZIP)) { + sysFlag |= MessageSysFlag.COMPRESSED_FLAG; + } + // transaction + MessageType messageType = protoMessage.getSystemProperties().getMessageType(); + if (messageType.equals(MessageType.TRANSACTION)) { + sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; + } + return sysFlag; + } + + protected Map buildMessageProperty(apache.rocketmq.v2.Message message, String producerGroup) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties Map userProperties = message.getUserPropertiesMap(); @@ -252,7 +253,7 @@ public class SendMessageActivity extends AbstractMessingActivity { @Override public SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { try { - Message message = request.getMessages(0); + apache.rocketmq.v2.Message message = request.getMessages(0); String shardingKey = null; if (request.getMessagesCount() == 1) { shardingKey = message.getSystemProperties().getMessageGroup(); 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 6a97754b01..6e26198bd2 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 @@ -18,8 +18,8 @@ package org.apache.rocketmq.proxy.processor; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.ServiceManager; @@ -41,16 +41,16 @@ public abstract class AbstractProcessor { } } - protected TopicMessageType parseFromMessageExt(MessageExt messageExt) { - String isTrans = messageExt.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); + protected TopicMessageType parseFromMessageExt(Message message) { + String isTrans = message.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); String isTransValue = "true"; if (isTransValue.equals(isTrans)) { return TopicMessageType.TRANSACTION; - } else if (messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null - || messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { + } else if (message.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null + || message.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS) != null + || message.getProperty(MessageConst.PROPERTY_TIMER_DELAY_SEC) != null) { return TopicMessageType.DELAY; - } else if (messageExt.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { + } else if (message.getProperty(MessageConst.PROPERTY_SHARDING_KEY) != null) { return TopicMessageType.FIFO; } else { return TopicMessageType.NORMAL; 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 b33c4f2042..0ae12c5c89 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 @@ -32,7 +32,7 @@ import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; @@ -126,8 +126,8 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen @Override public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector, - String producerGroup, List msg, long timeoutMillis) { - return this.producerProcessor.sendMessage(ctx, queueSelector, producerGroup, msg, timeoutMillis); + String producerGroup, int sysFlag, List msg, long timeoutMillis) { + return this.producerProcessor.sendMessage(ctx, queueSelector, producerGroup, sysFlag, msg, timeoutMillis); } @Override 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 07d28f8e46..5b2b9b2713 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 @@ -30,7 +30,7 @@ import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; @@ -63,16 +63,18 @@ public interface MessagingProcessor extends StartAndShutdown { ProxyContext ctx, QueueSelector queueSelector, String producerGroup, - List msg + int sysFlag, + List msg ) { - return sendMessage(ctx, queueSelector, producerGroup, msg, DEFAULT_TIMEOUT_MILLS); + return sendMessage(ctx, queueSelector, producerGroup, sysFlag, msg, DEFAULT_TIMEOUT_MILLS); } CompletableFuture> sendMessage( ProxyContext ctx, QueueSelector queueSelector, String producerGroup, - List msg, + int sysFlag, + List msg, long timeoutMillis ); 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 d9666559f2..f6c9e71298 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 @@ -25,10 +25,10 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; @@ -59,17 +59,17 @@ public class ProducerProcessor extends AbstractProcessor { } public CompletableFuture> sendMessage(ProxyContext ctx, QueueSelector queueSelector, - String producerGroup, List messageExtList, long timeoutMillis) { + String producerGroup, int sysFlag, List messageList, long timeoutMillis) { CompletableFuture> future = new CompletableFuture<>(); try { - MessageExt messageExt0 = messageExtList.get(0); - String topic = messageExt0.getTopic(); + Message message = messageList.get(0); + String topic = message.getTopic(); if (ConfigurationManager.getProxyConfig().isEnableTopicMessageTypeCheck()) { if (topicMessageTypeValidator != null) { // Do not check retry or dlq topic if (!NamespaceUtil.isRetryTopic(topic) && !NamespaceUtil.isDLQTopic(topic)) { TopicMessageType topicMessageType = serviceManager.getMetadataService().getTopicMessageType(topic); - TopicMessageType messageType = parseFromMessageExt(messageExt0); + TopicMessageType messageType = parseFromMessageExt(message); topicMessageTypeValidator.validate(topicMessageType, messageType); } } @@ -80,12 +80,12 @@ public class ProducerProcessor extends AbstractProcessor { throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no writable queue"); } - SendMessageRequestHeader requestHeader = buildSendMessageRequestHeader(messageExtList, producerGroup, messageQueue.getQueueId()); + SendMessageRequestHeader requestHeader = buildSendMessageRequestHeader(messageList, producerGroup, sysFlag, messageQueue.getQueueId()); future = this.serviceManager.getMessageService().sendMessage( ctx, messageQueue, - messageExtList, + messageList, requestHeader, timeoutMillis) .thenApplyAsync(sendResultList -> { @@ -106,23 +106,23 @@ public class ProducerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } - protected SendMessageRequestHeader buildSendMessageRequestHeader(List messageExtList, - String producerGroup, int queueId) { + protected SendMessageRequestHeader buildSendMessageRequestHeader(List messageList, + String producerGroup, int sysFlag, int queueId) { SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); - MessageExt message = messageExtList.get(0); + Message message = messageList.get(0); requestHeader.setProducerGroup(producerGroup); requestHeader.setTopic(message.getTopic()); requestHeader.setDefaultTopic(""); requestHeader.setDefaultTopicQueueNums(0); requestHeader.setQueueId(queueId); - requestHeader.setSysFlag(message.getSysFlag()); + requestHeader.setSysFlag(sysFlag); requestHeader.setBornTimestamp(System.currentTimeMillis()); requestHeader.setFlag(message.getFlag()); requestHeader.setProperties(MessageDecoder.messageProperties2String(message.getProperties())); requestHeader.setReconsumeTimes(0); - if (messageExtList.size() > 1) { + if (messageList.size() > 1) { requestHeader.setBatch(true); } if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { 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 3238c69ba1..15e3af47ca 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 @@ -53,7 +53,7 @@ public class ClusterMessageService implements MessageService { @Override public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, - List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { CompletableFuture> future; if (msgList.size() == 1) { future = this.mqClientAPIFactory.getClient().sendMessageAsync( 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 1c079d7fb3..ac4b4079be 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 @@ -77,7 +77,7 @@ public class LocalMessageService implements MessageService { @Override public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, - List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { byte[] body; String messageId; if (msgList.size() > 1) { 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 35f0ea147b..7c2d2ea9e5 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 @@ -41,7 +41,7 @@ public interface MessageService { CompletableFuture> sendMessage( ProxyContext ctx, SelectableMessageQueue messageQueue, - List msgList, + List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis ); 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 782aaa5e51..e4e87a221b 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 @@ -37,7 +37,6 @@ import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; @@ -55,6 +54,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -81,7 +81,7 @@ public class SendMessageActivityTest extends BaseActivityTest { SendResult sendResult = new SendResult(); sendResult.setSendStatus(SendStatus.SEND_OK); sendResult.setMsgId(msgId); - when(this.messagingProcessor.sendMessage(any(), any(), anyString(), any())) + when(this.messagingProcessor.sendMessage(any(), any(), anyString(), anyInt(), any())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); SendMessageResponse response = this.sendMessageActivity.sendMessage( @@ -201,7 +201,7 @@ public class SendMessageActivityTest extends BaseActivityTest { long deliveryTime = System.currentTimeMillis(); String msgId = MessageClientIDSetter.createUniqID(); - MessageExt messageExt = this.sendMessageActivity.buildMessage(null, + org.apache.rocketmq.common.message.Message messageExt = this.sendMessageActivity.buildMessage(null, Lists.newArrayList( Message.newBuilder() .setTopic(Resource.newBuilder() @@ -228,28 +228,29 @@ public class SendMessageActivityTest extends BaseActivityTest { public void testTxMessage() { String msgId = MessageClientIDSetter.createUniqID(); - MessageExt messageExt = this.sendMessageActivity.buildMessage(null, + Message message = Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(msgId) + .setQueueId(0) + .setMessageType(MessageType.TRANSACTION) + .setOrphanedTransactionRecoveryDuration(Durations.fromSeconds(30)) + .setBodyEncoding(Encoding.GZIP) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build(); + org.apache.rocketmq.common.message.Message messageExt = this.sendMessageActivity.buildMessage(null, Lists.newArrayList( - Message.newBuilder() - .setTopic(Resource.newBuilder() - .setName(TOPIC) - .build()) - .setSystemProperties(SystemProperties.newBuilder() - .setMessageId(msgId) - .setQueueId(0) - .setMessageType(MessageType.TRANSACTION) - .setOrphanedTransactionRecoveryDuration(Durations.fromSeconds(30)) - .setBodyEncoding(Encoding.GZIP) - .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) - .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) - .build()) - .setBody(ByteString.copyFromUtf8("123")) - .build() + message ), Resource.newBuilder().setName(TOPIC).build()).get(0); assertEquals(MessageClientIDSetter.getUniqID(messageExt), msgId); - assertEquals(MessageSysFlag.TRANSACTION_PREPARED_TYPE | MessageSysFlag.COMPRESSED_FLAG, messageExt.getSysFlag()); + assertEquals(MessageSysFlag.TRANSACTION_PREPARED_TYPE | MessageSysFlag.COMPRESSED_FLAG, sendMessageActivity.buildSysFlag(message)); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 5b66fa8ed0..9f47dd8003 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -27,6 +27,7 @@ import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; @@ -79,10 +80,9 @@ public class ProducerProcessorTest extends BaseProcessorTest { when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); - List messageExtList = new ArrayList<>(); - MessageExt messageExt = createMessageExt(TOPIC, "tag", 0, 0); - messageExt.setSysFlag(MessageSysFlag.TRANSACTION_PREPARED_TYPE); - messageExtList.add(messageExt); + List messageList = new ArrayList<>(); + Message messageExt = createMessageExt(TOPIC, "tag", 0, 0); + messageList.add(messageExt); SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); when(messageQueue.getBrokerName()).thenReturn("mockBroker"); @@ -90,7 +90,8 @@ public class ProducerProcessorTest extends BaseProcessorTest { createContext(), (ctx, messageQueueView) -> messageQueue, PRODUCER_GROUP, - messageExtList, + MessageSysFlag.TRANSACTION_PREPARED_TYPE, + messageList, 3000 ).get(); @@ -118,9 +119,8 @@ public class ProducerProcessorTest extends BaseProcessorTest { when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); - List messageExtList = new ArrayList<>(); - MessageExt messageExt = createMessageExt(MixAll.getRetryTopic(CONSUMER_GROUP), "tag", 0, 0); - messageExt.setSysFlag(MessageSysFlag.TRANSACTION_PREPARED_TYPE); + List messageExtList = new ArrayList<>(); + Message messageExt = createMessageExt(MixAll.getRetryTopic(CONSUMER_GROUP), "tag", 0, 0); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_RECONSUME_TIME, "1"); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_MAX_RECONSUME_TIMES, "16"); messageExtList.add(messageExt); @@ -131,6 +131,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { createContext(), (ctx, messageQueueView) -> messageQueue, PRODUCER_GROUP, + MessageSysFlag.TRANSACTION_PREPARED_TYPE, messageExtList, 3000 ).get(); From 2ede51068769973f1b9c201184648cefda939901 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 1 Jun 2022 11:34:27 +0800 Subject: [PATCH 240/338] [ISSUE #3949] Support autoRenew --- .../proxy/common/ContextVariable.java | 1 + .../proxy/common/MessageReceiptHandle.java | 86 ++++++++ .../proxy/common/ReceiptHandleGroup.java | 38 ++++ .../proxy/common/utils/ChannelUtils.java | 26 +++ .../rocketmq/proxy/config/ProxyConfig.java | 47 ++++ .../grpc/v2/AbstractMessingActivity.java | 15 +- .../grpc/v2/DefaultGrpcMessingActivity.java | 24 ++- .../proxy/grpc/v2/client/ClientActivity.java | 14 +- .../grpc/v2/consumer/AckMessageActivity.java | 31 ++- .../ChangeInvisibleDurationActivity.java | 21 +- .../v2/consumer/ReceiveMessageActivity.java | 48 ++++- .../producer/ForwardMessageToDLQActivity.java | 5 +- .../grpc/v2/producer/SendMessageActivity.java | 5 +- .../proxy/grpc/v2/route/RouteActivity.java | 5 +- .../transaction/EndTransactionActivity.java | 5 +- .../proxy/processor/AbstractProcessor.java | 3 +- .../proxy/processor/ConsumerProcessor.java | 4 +- .../processor/DefaultMessagingProcessor.java | 5 + .../proxy/processor/MessagingProcessor.java | 3 + .../processor/ReceiptHandleProcessor.java | 202 ++++++++++++++++++ .../proxy/service/channel/SimpleChannel.java | 7 +- .../proxy/service/relay/ProxyChannel.java | 20 +- .../proxy/grpc/v2/BaseActivityTest.java | 6 + .../grpc/v2/client/ClientActivityTest.java | 2 +- .../v2/consumer/AckMessageActivityTest.java | 2 +- .../ChangeInvisibleDurationActivityTest.java | 3 +- .../consumer/ReceiveMessageActivityTest.java | 6 +- .../ForwardMessageToDLQActivityTest.java | 2 +- .../v2/producer/SendMessageActivityTest.java | 2 +- .../grpc/v2/route/RouteActivityTest.java | 2 +- .../EndTransactionActivityTest.java | 2 +- .../proxy/processor/BaseProcessorTest.java | 1 + .../processor/ConsumerProcessorTest.java | 3 +- .../processor/ReceiptHandleProcessorTest.java | 192 +++++++++++++++++ 34 files changed, 753 insertions(+), 85 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index 27cc04cc2a..df102b9648 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -22,4 +22,5 @@ public class ContextVariable { public final static String LOCAL_ADDRESS = "local-address"; public static final String CLIENT_ID = "client-id"; public static final String LANGUAGE = "language"; + public final static String CHANNEL_KEY = "channel-key"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java new file mode 100644 index 0000000000..4c396e71d0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java @@ -0,0 +1,86 @@ +/* + * 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.common; + +import org.apache.rocketmq.common.message.MessageQueue; + +public class MessageReceiptHandle { + private final String group; + private final MessageQueue messageQueue; + private final String messageId; + private final long queueOffset; + private final String originalReceiptHandle; + private final long timestamp; + private final int reconsumeTimes; + private final long expectInvisibleTime; + + private String receiptHandle; + + public MessageReceiptHandle(String group, MessageQueue messageQueue, String receiptHandle, String messageId, + long queueOffset, int reconsumeTimes, long expectInvisibleTime) { + this.group = group; + this.messageQueue = messageQueue; + this.receiptHandle = receiptHandle; + this.originalReceiptHandle = receiptHandle; + this.messageId = messageId; + this.queueOffset = queueOffset; + this.reconsumeTimes = reconsumeTimes; + this.expectInvisibleTime = expectInvisibleTime; + this.timestamp = System.currentTimeMillis(); + } + + public String getGroup() { + return group; + } + + public MessageQueue getMessageQueue() { + return messageQueue; + } + + public String getReceiptHandle() { + return receiptHandle; + } + + public String getOriginalReceiptHandle() { + return originalReceiptHandle; + } + + public String getMessageId() { + return messageId; + } + + public long getQueueOffset() { + return queueOffset; + } + + public int getReconsumeTimes() { + return reconsumeTimes; + } + + public long getTimestamp() { + return timestamp; + } + + public long getExpectInvisibleTime() { + return expectInvisibleTime; + } + + public void update(String receiptHandle) { + this.receiptHandle = receiptHandle; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java new file mode 100644 index 0000000000..71e23932b3 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.common; + +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ReceiptHandleGroup { + private final Map receiptHandleMap = new ConcurrentHashMap<>(); + + public void put(String key, MessageReceiptHandle value) { + receiptHandleMap.put(key, value); + } + + public void remove(String key) { + receiptHandleMap.remove(key); + } + + public Map all() { + return ImmutableMap.copyOf(receiptHandleMap); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java new file mode 100644 index 0000000000..632506ee77 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.common.utils; + +import io.netty.channel.Channel; + +public class ChannelUtils { + public static String buildChannelKey(Channel channel, String groupName) { + return channel.id().asLongText() + "%" + groupName; + } +} 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 49e7b4ae80..7b66e037c2 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 @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.config; import java.time.Duration; +import java.util.concurrent.TimeUnit; import org.apache.rocketmq.proxy.ProxyMode; public class ProxyConfig { @@ -97,6 +98,12 @@ public class ProxyConfig { private long longPollingReserveTimeInMillis = 100; + private long invisibleTimeMillisWhenClear = 1000L; + private boolean enableProxyAutoRenew = true; + private long renewAheadTimeMillis = TimeUnit.SECONDS.toMillis(10); + private long renewSliceTimeMillis = TimeUnit.SECONDS.toMillis(60); + private long renewSchedulePeriodMillis = TimeUnit.SECONDS.toMillis(5); + private boolean enableACL = false; private boolean enableTopicMessageTypeCheck = true; @@ -532,4 +539,44 @@ public class ProxyConfig { public void setEnableTopicMessageTypeCheck(boolean enableTopicMessageTypeCheck) { this.enableTopicMessageTypeCheck = enableTopicMessageTypeCheck; } + + public long getInvisibleTimeMillisWhenClear() { + return invisibleTimeMillisWhenClear; + } + + public void setInvisibleTimeMillisWhenClear(long invisibleTimeMillisWhenClear) { + this.invisibleTimeMillisWhenClear = invisibleTimeMillisWhenClear; + } + + public boolean isEnableProxyAutoRenew() { + return enableProxyAutoRenew; + } + + public void setEnableProxyAutoRenew(boolean enableProxyAutoRenew) { + this.enableProxyAutoRenew = enableProxyAutoRenew; + } + + public long getRenewAheadTimeMillis() { + return renewAheadTimeMillis; + } + + public void setRenewAheadTimeMillis(long renewAheadTimeMillis) { + this.renewAheadTimeMillis = renewAheadTimeMillis; + } + + public long getRenewSliceTimeMillis() { + return renewSliceTimeMillis; + } + + public void setRenewSliceTimeMillis(long renewSliceTimeMillis) { + this.renewSliceTimeMillis = renewSliceTimeMillis; + } + + public long getRenewSchedulePeriodMillis() { + return renewSchedulePeriodMillis; + } + + public void setRenewSchedulePeriodMillis(long renewSchedulePeriodMillis) { + this.renewSchedulePeriodMillis = renewSchedulePeriodMillis; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 7ca356df12..6e94e68723 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -17,9 +17,12 @@ package org.apache.rocketmq.proxy.grpc.v2; import io.grpc.Context; +import io.netty.channel.Channel; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.utils.ChannelUtils; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.remoting.protocol.LanguageCode; @@ -28,16 +31,26 @@ public abstract class AbstractMessingActivity { protected final MessagingProcessor messagingProcessor; protected final GrpcClientSettingsManager grpcClientSettingsManager; + protected final GrpcChannelManager grpcChannelManager; public AbstractMessingActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { this.messagingProcessor = messagingProcessor; this.grpcClientSettingsManager = grpcClientSettingsManager; + this.grpcChannelManager = grpcChannelManager; } protected ProxyContext createContext(Context ctx) { return ProxyContext.create() + .withVal(ContextVariable.LOCAL_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)) + .withVal(ContextVariable.REMOTE_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS)) .withVal(ContextVariable.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) .withVal(ContextVariable.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); } + + protected void attachChannelId(Context ctx, ProxyContext context, String groupName) { + String clientId = context.getVal(ContextVariable.CLIENT_ID); + Channel channel = grpcChannelManager.createChannel(ctx, groupName, clientId); + context.withVal(ContextVariable.CHANNEL_KEY, ChannelUtils.buildChannelKey(channel, groupName)); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 1422c01e78..9ac1001e6d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -44,6 +44,7 @@ import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.client.ClientActivity; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.grpc.v2.consumer.AckMessageActivity; @@ -54,12 +55,11 @@ import org.apache.rocketmq.proxy.grpc.v2.producer.SendMessageActivity; import org.apache.rocketmq.proxy.grpc.v2.route.RouteActivity; import org.apache.rocketmq.proxy.grpc.v2.transaction.EndTransactionActivity; import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final GrpcClientSettingsManager grpcClientSettingsManager; - private final ReceiveMessageActivity receiveMessageActivity; private final AckMessageActivity ackMessageActivity; private final ChangeInvisibleDurationActivity changeInvisibleDurationActivity; @@ -70,16 +70,18 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme private final ClientActivity clientActivity; protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { - this.grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); + GrpcClientSettingsManager grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); + GrpcChannelManager grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); + ReceiptHandleProcessor receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); - this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, this.grpcClientSettingsManager); - this.ackMessageActivity = new AckMessageActivity(messagingProcessor, this.grpcClientSettingsManager); - this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(messagingProcessor, this.grpcClientSettingsManager); - this.sendMessageActivity = new SendMessageActivity(messagingProcessor, this.grpcClientSettingsManager); - this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(messagingProcessor, this.grpcClientSettingsManager); - this.endTransactionActivity = new EndTransactionActivity(messagingProcessor, this.grpcClientSettingsManager); - this.routeActivity = new RouteActivity(messagingProcessor, this.grpcClientSettingsManager); - this.clientActivity = new ClientActivity(messagingProcessor, this.grpcClientSettingsManager); + this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); + this.ackMessageActivity = new AckMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); + this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); + this.sendMessageActivity = new SendMessageActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.endTransactionActivity = new EndTransactionActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.routeActivity = new RouteActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.clientActivity = new ClientActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 86b9652c66..9131da633d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -71,22 +71,10 @@ public class ClientActivity extends AbstractMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final GrpcChannelManager grpcChannelManager; - public ClientActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); - - this.grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); - - this.init(); - } - - ClientActivity(MessagingProcessor messagingProcessor, GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { - super(messagingProcessor, grpcClientSettingsManager); - this.grpcChannelManager = grpcChannelManager; + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); this.init(); } 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 42cc3a8645..e76dc42780 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 @@ -30,22 +30,29 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; 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.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class AckMessageActivity extends AbstractMessingActivity { - - public AckMessageActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + protected ReceiptHandleProcessor receiptHandleProcessor; + public AckMessageActivity(MessagingProcessor messagingProcessor, ReceiptHandleProcessor receiptHandleProcessor, + GrpcClientSettingsManager grpcClientSettingsManager, + GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.receiptHandleProcessor = receiptHandleProcessor; } public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { ProxyContext proxyContext = createContext(ctx); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + attachChannelId(ctx, proxyContext, groupName); CompletableFuture future = new CompletableFuture<>(); try { @@ -101,12 +108,16 @@ public class AckMessageActivity extends AbstractMessingActivity { ackMessageEntry.getMessageId(), GrpcConverter.wrapResourceWithNamespace(request.getGroup()), GrpcConverter.wrapResourceWithNamespace(request.getTopic())); - ackResultFuture - .thenAccept(result -> future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result))) - .exceptionally(throwable -> { - future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); - return null; - }); + ackResultFuture.thenAccept(result -> { + if (AckStatus.OK.equals(result.getStatus())) { + String channelId = ctx.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.removeReceiptHandle(channelId, ackMessageEntry.getReceiptHandle()); + } + future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); + }).exceptionally(throwable -> { + future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); + return null; + }); } catch (Throwable t) { future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index fc8fb405f7..f6f2bbec18 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -25,23 +25,30 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; 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.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { + protected ReceiptHandleProcessor receiptHandleProcessor; - public ChangeInvisibleDurationActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + public ChangeInvisibleDurationActivity(MessagingProcessor messagingProcessor, ReceiptHandleProcessor receiptHandleProcessor, + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.receiptHandleProcessor = receiptHandleProcessor; } public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { ProxyContext context = createContext(ctx); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + attachChannelId(ctx, context, groupName); CompletableFuture future = new CompletableFuture<>(); try { @@ -54,7 +61,13 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { GrpcConverter.wrapResourceWithNamespace(request.getGroup()), GrpcConverter.wrapResourceWithNamespace(request.getTopic()), Durations.toMillis(request.getInvisibleDuration()) - ).thenApply(ackResult -> convertToChangeInvisibleDurationResponse(context, request, ackResult)); + ).thenApply(ackResult -> { + if (AckStatus.OK.equals(ackResult.getStatus())) { + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.removeReceiptHandle(channelId, receiptHandle.getReceiptHandle()); + } + return convertToChangeInvisibleDurationResponse(context, request, ackResult); + }); } catch (Throwable t) { future.completeExceptionally(t); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 3c8b045a07..42808961ce 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -25,33 +25,46 @@ import apache.rocketmq.v2.Subscription; import com.google.protobuf.util.Durations; import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.filter.FilterAPI; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.ContextVariable; +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.config.ProxyConfig; 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.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; +import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; import org.apache.rocketmq.proxy.service.route.MessageQueueSelector; import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; public class ReceiveMessageActivity extends AbstractMessingActivity { + protected ReceiptHandleProcessor receiptHandleProcessor; - public ReceiveMessageActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + public ReceiveMessageActivity(MessagingProcessor messagingProcessor, ReceiptHandleProcessor receiptHandleProcessor, + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + this.receiptHandleProcessor = receiptHandleProcessor; } public void receiveMessage(Context ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { ProxyContext proxyContext = createContext(ctx); ReceiveMessageResponseStreamWriter writer = createWriter(proxyContext, responseObserver); + String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + attachChannelId(ctx, proxyContext, groupName); try { Settings settings = this.grpcClientSettingsManager.getClientSettings(proxyContext); @@ -68,10 +81,11 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { return; } - long invisibleTime = Durations.toMillis(request.getInvisibleDuration()); - if (request.getAutoRenew()) { - invisibleTime = Durations.toMillis(subscription.getLongPollingTimeout() - ); + final long requestInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); + long actualInvisibleTime = requestInvisibleTime; + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { + actualInvisibleTime = Math.min(actualInvisibleTime, proxyConfig.getRenewSliceTimeMillis()); } String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); @@ -94,14 +108,30 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { group, topic, request.getBatchSize(), - invisibleTime, + actualInvisibleTime, pollTime, ConsumeInitMode.MAX, subscriptionData, fifo, new PopMessageResultFilterImpl(grpcClientSettingsManager), timeRemaining - ).thenAccept(popResult -> writer.writeAndComplete(proxyContext, request, popResult)) + ).thenAccept(popResult -> { + if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { + List messageExtList = popResult.getMsgFoundList(); + for (MessageExt messageExt : messageExtList) { + String receiptHandle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (receiptHandle != null) { + MessageQueue messageQueue = new MessageQueue(topic, messageExt.getBrokerName(), messageExt.getQueueId()); + MessageReceiptHandle messageReceiptHandle = + new MessageReceiptHandle(group, messageQueue, receiptHandle, messageExt.getMsgId(), + messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); + String channelId = proxyContext.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + } + } + } + writer.writeAndComplete(proxyContext, request, popResult); + }) .exceptionally(t -> { writer.writeAndComplete(proxyContext, request, t); return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java index d6133ded44..ed7f64d32d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -23,6 +23,7 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.common.ProxyContext; 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; @@ -32,8 +33,8 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ForwardMessageToDLQActivity extends AbstractMessingActivity { public ForwardMessageToDLQActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, 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 50419381c2..5435900416 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 @@ -44,6 +44,7 @@ import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; 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.GrpcProxyException; @@ -56,8 +57,8 @@ import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; public class SendMessageActivity extends AbstractMessingActivity { public SendMessageActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index a36608614a..f6f9982a59 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -41,6 +41,7 @@ import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.proxy.common.ProxyContext; 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; @@ -51,8 +52,8 @@ import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; public class RouteActivity extends AbstractMessingActivity { public RouteActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index 35c6a02218..d33f1e0a11 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -25,6 +25,7 @@ import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.ProxyContext; 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; @@ -35,8 +36,8 @@ import org.apache.rocketmq.proxy.service.transaction.TransactionId; public class EndTransactionActivity extends AbstractMessingActivity { public EndTransactionActivity(MessagingProcessor messagingProcessor, - GrpcClientSettingsManager grpcClientSettingsManager) { - super(messagingProcessor, grpcClientSettingsManager); + GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { 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 6e26198bd2..4815d7dbaf 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 @@ -20,11 +20,12 @@ import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.ServiceManager; -public abstract class AbstractProcessor { +public abstract class AbstractProcessor extends AbstractStartAndShutdown { protected MessagingProcessor messagingProcessor; protected ServiceManager serviceManager; 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 63e51f3ea1..8dfe714200 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 @@ -46,8 +46,8 @@ public class ConsumerProcessor extends AbstractProcessor { private final ExecutorService executor; - public ConsumerProcessor(MessagingProcessor messagingProcessor, - ServiceManager serviceManager, ExecutorService executor) { + public ConsumerProcessor(MessagingProcessor messagingProcessor, ServiceManager serviceManager, + ExecutorService executor) { super(messagingProcessor, serviceManager); this.executor = executor; } 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 0ae12c5c89..628f1af73d 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 @@ -45,6 +45,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; 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.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -226,4 +227,8 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen return this.serviceManager.getProxyRelayService(); } + @Override + public MetadataService getMetadataService() { + return this.serviceManager.getMetadataService(); + } } 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 5b2b9b2713..c01e9c882a 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 @@ -38,6 +38,7 @@ import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.Address; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -228,4 +229,6 @@ public interface MessagingProcessor extends StartAndShutdown { ); ProxyRelayService getProxyOutService(); + + MetadataService getMetadataService(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java new file mode 100644 index 0000000000..6b2aaca25e --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -0,0 +1,202 @@ +/* + * 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 io.netty.channel.Channel; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +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.TimeUnit; +import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupEvent; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.common.ThreadFactoryImpl; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.subscription.RetryPolicy; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.MessageReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.ReceiptHandleGroup; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.common.utils.ChannelUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReceiptHandleProcessor extends AbstractStartAndShutdown { + protected final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected final ConcurrentMap receiptHandleGroupMap; + protected final ScheduledExecutorService scheduledExecutorService = + Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("RenewalScheduledThread_")); + protected final ExecutorService renewalWorkerService = ThreadPoolMonitor.createAndMonitor( + 2, 4, 0, TimeUnit.MILLISECONDS, + "RenewalWorkerThread_", 10000 + ); + protected final MessagingProcessor messagingProcessor; + + public ReceiptHandleProcessor(MessagingProcessor messagingProcessor) { + this.messagingProcessor = messagingProcessor; + this.messagingProcessor.registerConsumerListener(new ConsumerIdsChangeListener() { + @Override + public void handle(ConsumerGroupEvent event, String group, Object... args) { + if (ConsumerGroupEvent.CLIENT_UNREGISTER.equals(event)) { + if (args == null || args.length < 1) { + return; + } + if (args[0] instanceof ClientChannelInfo) { + ClientChannelInfo clientChannelInfo = (ClientChannelInfo) args[0]; + Channel channel = clientChannelInfo.getChannel(); + clearGroup(ChannelUtils.buildChannelKey(channel, group)); + } + } + } + + @Override + public void shutdown() { + + } + }); + this.receiptHandleGroupMap = new ConcurrentHashMap<>(); + this.init(); + } + + protected void init() { + this.appendStartAndShutdown(new StartAndShutdown() { + @Override + public void start() throws Exception { + log.info("scan for renewal start."); + scheduledExecutorService.scheduleAtFixedRate(() -> scheduleRenewTask(), 0, + ConfigurationManager.getProxyConfig().getRenewSchedulePeriodMillis(), TimeUnit.MILLISECONDS); + log.info("renewal queue has started"); + } + + @Override + public void shutdown() throws Exception { + scheduledExecutorService.shutdown(); + } + }); + } + + protected void scheduleRenewTask() { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + for (Map.Entry entry : receiptHandleGroupMap.entrySet()) { + String key = entry.getKey(); + ReceiptHandleGroup group = entry.getValue(); + group.all().forEach((k, v) -> { + ReceiptHandle handle = ReceiptHandle.decode(v.getReceiptHandle()); + long now = System.currentTimeMillis(); + if (handle.getNextVisibleTime() - now > proxyConfig.getRenewAheadTimeMillis()) { + return; + } + SubscriptionGroupConfig subscriptionGroupConfig = + messagingProcessor.getMetadataService().getSubscriptionGroupConfig(v.getGroup()); + if (subscriptionGroupConfig == null) { + log.error("Group's subscriptionGroupConfig is null, group = {}", v.getGroup()); + return; + } + RetryPolicy retryPolicy = subscriptionGroupConfig.getGroupRetryPolicy().getRetryPolicy(); + renewalWorkerService.submit(() -> renewMessage(key, v, handle, retryPolicy)); + }); + } + + log.info("scan for renewal done."); + } + + protected void renewMessage(String key, MessageReceiptHandle messageReceiptHandle, + ReceiptHandle handle, RetryPolicy retryPolicy) { + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + long current = System.currentTimeMillis(); + if (current - messageReceiptHandle.getTimestamp() < messageReceiptHandle.getExpectInvisibleTime()) { + CompletableFuture future = + messagingProcessor.changeInvisibleTime(ProxyContext.create(), handle, messageReceiptHandle.getMessageId(), + messageReceiptHandle.getGroup(), messageReceiptHandle.getMessageQueue().getTopic(), proxyConfig.getRenewSliceTimeMillis()); + future.thenAccept(ackResult -> { + if (AckStatus.OK.equals(ackResult.getStatus())) { + messageReceiptHandle.update(ackResult.getExtraInfo()); + addReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle(), messageReceiptHandle); + } + }); + } else { + CompletableFuture future = messagingProcessor.changeInvisibleTime(ProxyContext.create(), + handle, messageReceiptHandle.getMessageId(), messageReceiptHandle.getGroup(), + messageReceiptHandle.getMessageQueue().getTopic(), + retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes(), TimeUnit.MILLISECONDS)); + future.thenAccept(ackResult -> { + if (AckStatus.OK.equals(ackResult.getStatus())) { + removeReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle()); + } + }); + } + } + + public void addReceiptHandle(String key, String receiptHandle, + MessageReceiptHandle messageReceiptHandle) { + if (key == null) { + return; + } + receiptHandleGroupMap.computeIfAbsent(key, + k -> new ReceiptHandleGroup()).put(receiptHandle, messageReceiptHandle); + } + + public void removeReceiptHandle(String key, String receiptHandle) { + if (key == null) { + return; + } + receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { + v.remove(receiptHandle); + return v; + }); + } + + public void clearGroup(String key) { + if (key == null) { + return; + } + ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { + Map all = v.all(); + all.forEach((key0, value0) -> { + ReceiptHandle receiptHandle = ReceiptHandle.decode(value0.getReceiptHandle()); + messagingProcessor.changeInvisibleTime( + ProxyContext.create(), + receiptHandle, + value0.getMessageId(), + value0.getGroup(), + value0.getMessageQueue().getTopic(), + proxyConfig.getInvisibleTimeMillisWhenClear() + ); + }); + return null; + } + ); + } + + protected String keyWithChannelId(String channelId, String groupName) { + return channelId + "%" + groupName; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java index 4b700c5ed7..35e817b5a2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/SimpleChannel.java @@ -23,6 +23,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelId; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.DefaultChannelPromise; @@ -57,7 +58,11 @@ public class SimpleChannel extends AbstractChannel { * @param localAddress Local address */ public SimpleChannel(Channel parent, String remoteAddress, String localAddress) { - super(parent); + this(parent, null, remoteAddress, localAddress); + } + + public SimpleChannel(Channel parent, ChannelId id, String remoteAddress, String localAddress) { + super(parent, id); lastAccessTime = System.currentTimeMillis(); this.remoteAddress = remoteAddress; this.localAddress = localAddress; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 12a6ae6541..fb2d0b091c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.service.relay; -import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelFuture; @@ -43,36 +42,29 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public abstract class ProxyChannel extends AbstractChannel { +public abstract class ProxyChannel extends SimpleChannel { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - protected final String remoteAddress; protected final SocketAddress remoteSocketAddress; - protected final String localAddress; protected final SocketAddress localSocketAddress; protected final ProxyRelayService proxyRelayService; - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, - String localAddress) { - super(parent); + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, String localAddress) { + super(parent, remoteAddress, localAddress); this.proxyRelayService = proxyRelayService; - this.remoteAddress = remoteAddress; this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); - this.localAddress = localAddress; this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, - String localAddress) { - super(parent, id); + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, String localAddress) { + super(parent, id, remoteAddress, localAddress); this.proxyRelayService = proxyRelayService; - this.remoteAddress = remoteAddress; this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); - this.localAddress = localAddress; this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index bb28e43aea..86ecf5da57 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -26,8 +26,10 @@ import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.junit.Ignore; import org.junit.runner.RunWith; @@ -42,7 +44,9 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { protected static final Random RANDOM = new Random(); protected MessagingProcessor messagingProcessor; protected GrpcClientSettingsManager grpcClientSettingsManager; + protected GrpcChannelManager grpcChannelManager; protected ProxyRelayService proxyRelayService; + protected ReceiptHandleProcessor receiptHandleProcessor; protected static final String REMOTE_ADDR = "192.168.0.1:8080"; protected static final String LOCAL_ADDR = "127.0.0.1:8080"; @@ -55,12 +59,14 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { messagingProcessor = mock(MessagingProcessor.class); grpcClientSettingsManager = mock(GrpcClientSettingsManager.class); proxyRelayService = mock(ProxyRelayService.class); + receiptHandleProcessor = mock(ReceiptHandleProcessor.class); metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); when(messagingProcessor.getProxyOutService()).thenReturn(proxyRelayService); + grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); } protected Context createContext() { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index 242d62ee5a..15bde9918d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -89,7 +89,7 @@ public class ClientActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager, grpcChannelManager); } protected TelemetryCommand sendProducerTelemetry(Context context) throws Throwable { 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 d4a34cbb0c..523c30bfcf 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 @@ -45,7 +45,7 @@ public class AckMessageActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.ackMessageActivity = new AckMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.ackMessageActivity = new AckMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java index 4d6655530f..79a8648408 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java @@ -45,7 +45,8 @@ public class ChangeInvisibleDurationActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.changeInvisibleDurationActivity = new ChangeInvisibleDurationActivity(messagingProcessor, receiptHandleProcessor, + grpcClientSettingsManager, grpcChannelManager); } @Test 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 40a5ed4243..ae8ac2b684 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 @@ -69,7 +69,8 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.receiveMessageActivity = new ReceiveMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, receiptHandleProcessor, + grpcClientSettingsManager, grpcChannelManager); } @Test @@ -117,8 +118,7 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { any(), anyBoolean(), any(), - anyLong() - )).thenReturn(CompletableFuture.completedFuture(popResult)); + anyLong())).thenReturn(CompletableFuture.completedFuture(popResult)); this.receiveMessageActivity.receiveMessage( createContext(), diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java index 1bae776f9c..3e2a0b4200 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivityTest.java @@ -41,7 +41,7 @@ public class ForwardMessageToDLQActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.forwardMessageToDLQActivity = new ForwardMessageToDLQActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } @Test 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 e4e87a221b..8ee4433763 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 @@ -71,7 +71,7 @@ public class SendMessageActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.sendMessageActivity = new SendMessageActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.sendMessageActivity = new SendMessageActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index 583dbc995e..8d10efb135 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -77,7 +77,7 @@ public class RouteActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.routeActivity = new RouteActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.routeActivity = new RouteActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java index a2444a6e88..aa009ef7ae 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java @@ -60,7 +60,7 @@ public class EndTransactionActivityTest extends BaseActivityTest { @Before public void before() throws Throwable { super.before(); - this.endTransactionActivity = new EndTransactionActivity(this.messagingProcessor, this.grpcClientSettingsManager); + this.endTransactionActivity = new EndTransactionActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } @Test 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 f67d861158..58d7dce874 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 @@ -83,6 +83,7 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { when(serviceManager.getTransactionService()).thenReturn(transactionService); when(serviceManager.getProxyRelayService()).thenReturn(proxyRelayService); when(serviceManager.getMetadataService()).thenReturn(metadataService); + when(messagingProcessor.getMetadataService()).thenReturn(metadataService); } protected static ProxyContext createContext() { 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 35ab32a9e9..99ebba4223 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 @@ -64,7 +64,8 @@ public class ConsumerProcessorTest extends BaseProcessorTest { @Before public void before() throws Throwable { super.before(); - this.consumerProcessor = new ConsumerProcessor(this.messagingProcessor, this.serviceManager, Executors.newCachedThreadPool()); + ReceiptHandleProcessor receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); + this.consumerProcessor = new ConsumerProcessor(messagingProcessor, serviceManager, Executors.newCachedThreadPool()); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java new file mode 100644 index 0000000000..73c05a6784 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.processor; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; +import org.apache.rocketmq.client.consumer.AckResult; +import org.apache.rocketmq.client.consumer.AckStatus; +import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.proxy.common.ContextVariable; +import org.apache.rocketmq.proxy.common.MessageReceiptHandle; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class ReceiptHandleProcessorTest extends BaseProcessorTest { + ReceiptHandleProcessor receiptHandleProcessor; + + ProxyContext context = ProxyContext.create(); + String group = "group"; + MessageQueue messageQueue = new MessageQueue("topic", "broker", 1); + String messageId = "messageId"; + long offset = 123L; + long invisibleTime = 100000L; + int reconsumeTimes = 1; + MessageReceiptHandle messageReceiptHandle; + + String receiptHandle = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0) + .invisibleTime(invisibleTime) + .reviveQueueId(1) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(messageQueue.getBrokerName()) + .queueId(messageQueue.getQueueId()) + .offset(offset) + .commitLogOffset(0L) + .build().encode(); + + @Before + public void setup() { + context.withVal(ContextVariable.CHANNEL_KEY, "channel-id"); + receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); + Mockito.doNothing().when(messagingProcessor).registerConsumerListener(Mockito.any(ConsumerIdsChangeListener.class)); + messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, receiptHandle, messageId, offset, + reconsumeTimes, invisibleTime); + } + + @Test + public void testAddReceiptHandle() { + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(new SubscriptionGroupConfig()); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + } + + @Test + public void testRenewReceiptHandle() { + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + long newInvisibleTime = 2000L; + ReceiptHandle newReceiptHandleClass = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0) + .invisibleTime(newInvisibleTime) + .reviveQueueId(1) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(messageQueue.getBrokerName()) + .queueId(messageQueue.getQueueId()) + .offset(offset) + .commitLogOffset(0L) + .build(); + String newReceiptHandle = newReceiptHandleClass.encode(); + AckResult ackResult = new AckResult(); + ackResult.setStatus(AckStatus.OK); + ackResult.setExtraInfo(newReceiptHandle); + Mockito.when(messagingProcessor.changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis()))) + .thenReturn(CompletableFuture.completedFuture(ackResult)); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == invisibleTime), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + } + + @Test + public void testRenewReceiptHandleWhenTimeout() { + long newInvisibleTime = 0L; + String newReceiptHandle = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(0) + .invisibleTime(newInvisibleTime) + .reviveQueueId(1) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(messageQueue.getBrokerName()) + .queueId(messageQueue.getQueueId()) + .offset(offset) + .commitLogOffset(0L) + .build().encode(); + messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, receiptHandle, messageId, offset, + reconsumeTimes, newInvisibleTime); + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); + SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes, TimeUnit.MILLISECONDS))); + } + + + @Test + public void testRenewReceiptHandleWhenNotArrivingTime() { + String newReceiptHandle = ReceiptHandle.builder() + .startOffset(0L) + .retrieveTime(System.currentTimeMillis()) + .invisibleTime(invisibleTime) + .reviveQueueId(1) + .topicType(ReceiptHandle.NORMAL_TOPIC) + .brokerName(messageQueue.getBrokerName()) + .queueId(messageQueue.getQueueId()) + .offset(offset) + .commitLogOffset(0L) + .build().encode(); + messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, newReceiptHandle, messageId, offset, + reconsumeTimes, invisibleTime); + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); + SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(0)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), Mockito.anyLong()); + } + + @Test + public void testRemoveReceiptHandle() { + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.removeReceiptHandle(channelId, receiptHandle); + SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(0)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.anyString(), + Mockito.anyString(), Mockito.anyString(), Mockito.anyLong()); + } + + @Test + public void testClearGroup() { + String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.clearGroup(channelId); + SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + receiptHandleProcessor.scheduleRenewTask(); + Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), + Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getInvisibleTimeMillisWhenClear())); + } +} \ No newline at end of file From e5430c56262af9769ece6645338a1e504f2516af Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 8 Jun 2022 20:27:11 +0800 Subject: [PATCH 241/338] [ISSUE #3949] Add build method for ProxyTopicRouteData --- .../service/route/ProxyTopicRouteData.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java index 40bd844f4e..92931589d8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/ProxyTopicRouteData.java @@ -20,7 +20,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.Address; public class ProxyTopicRouteData { @@ -53,6 +56,20 @@ public class ProxyTopicRouteData { public void setBrokerAddrs(Map> brokerAddrs) { this.brokerAddrs = brokerAddrs; } + + public BrokerData buildBrokerData() { + BrokerData brokerData = new BrokerData(); + brokerData.setCluster(cluster); + brokerData.setBrokerName(brokerName); + HashMap buildBrokerAddress = new HashMap<>(); + brokerAddrs.forEach((k, v) -> { + if (!v.isEmpty()) { + buildBrokerAddress.put(k, v.get(0).getHostAndPort().toString()); + } + }); + brokerData.setBrokerAddrs(buildBrokerAddress); + return brokerData; + } } private List queueDatas = new ArrayList<>(); @@ -70,8 +87,16 @@ public class ProxyTopicRouteData { return brokerDatas; } - public void setBrokerDatas( - List brokerDatas) { + public void setBrokerDatas(List brokerDatas) { this.brokerDatas = brokerDatas; } + + public TopicRouteData buildTopicRouteData() { + TopicRouteData topicRouteData = new TopicRouteData(); + topicRouteData.setQueueDatas(queueDatas); + topicRouteData.setBrokerDatas(brokerDatas.stream() + .map(ProxyBrokerData::buildBrokerData) + .collect(Collectors.toList())); + return topicRouteData; + } } From c3059933e5ba6f1220d49bbc4e931d892d04e754 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 9 Jun 2022 14:16:52 +0800 Subject: [PATCH 242/338] [ISSUE #3949] Update maven-checkstyle-plugin version --- .../rocketmq/example/namespace/PullConsumerWithNamespace.java | 2 +- .../rocketmq/example/namespace/PushConsumerWithNamespace.java | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/src/main/java/org/apache/rocketmq/example/namespace/PullConsumerWithNamespace.java b/example/src/main/java/org/apache/rocketmq/example/namespace/PullConsumerWithNamespace.java index f8bf0230d5..d2a17b3a08 100644 --- a/example/src/main/java/org/apache/rocketmq/example/namespace/PullConsumerWithNamespace.java +++ b/example/src/main/java/org/apache/rocketmq/example/namespace/PullConsumerWithNamespace.java @@ -79,7 +79,7 @@ public class PullConsumerWithNamespace { return; } pullResult.getMsgFoundList().stream().forEach( - (msg) -> System.out.printf("Topic is:%s, msgId is:%s%n" , msg.getTopic(), msg.getMsgId())); + msg -> System.out.printf("Topic is:%s, msgId is:%s%n" , msg.getTopic(), msg.getMsgId())); } private static void putMessageQueueOffset(MessageQueue mq, long offset) { diff --git a/example/src/main/java/org/apache/rocketmq/example/namespace/PushConsumerWithNamespace.java b/example/src/main/java/org/apache/rocketmq/example/namespace/PushConsumerWithNamespace.java index 40f1db2e71..f1e4ffc1af 100644 --- a/example/src/main/java/org/apache/rocketmq/example/namespace/PushConsumerWithNamespace.java +++ b/example/src/main/java/org/apache/rocketmq/example/namespace/PushConsumerWithNamespace.java @@ -26,7 +26,7 @@ public class PushConsumerWithNamespace { defaultMQPushConsumer.setNamesrvAddr("127.0.0.1:9876"); defaultMQPushConsumer.subscribe("topicTest", "*"); defaultMQPushConsumer.registerMessageListener((MessageListenerConcurrently)(msgs, context) -> { - msgs.stream().forEach((msg) -> { + msgs.stream().forEach(msg -> { System.out.printf("Msg topic is:%s, MsgId is:%s, reconsumeTimes is:%s%n", msg.getTopic() , msg.getMsgId(), msg.getReconsumeTimes()); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; diff --git a/pom.xml b/pom.xml index 93f58dac08..f8de8d13cc 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ maven-checkstyle-plugin - 2.17 + 3.1.2 verify From 67f92fbdf3f7ec5ab1f00c766db9210ac741e7a2 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 9 Jun 2022 16:29:34 +0800 Subject: [PATCH 243/338] [ISSUE #3949] Add getConsumerGroupInfo --- .../apache/rocketmq/proxy/processor/ClientProcessor.java | 5 +++++ .../rocketmq/proxy/processor/DefaultMessagingProcessor.java | 6 ++++++ .../apache/rocketmq/proxy/processor/MessagingProcessor.java | 3 +++ 3 files changed, 14 insertions(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java index ea6f253f8e..f56627a257 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.processor; import io.netty.channel.Channel; import java.util.Set; import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupInfo; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; @@ -101,4 +102,8 @@ public class ClientProcessor extends AbstractProcessor { public void registerConsumerIdsChangeListener(ConsumerIdsChangeListener listener) { this.serviceManager.getConsumerManager().appendConsumerIdsChangeListener(listener); } + + public ConsumerGroupInfo getConsumerGroupInfo(String consumerGroup) { + return this.serviceManager.getConsumerManager().getConsumerGroupInfo(consumerGroup); + } } 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 628f1af73d..5e5ce2e39b 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 @@ -24,6 +24,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupInfo; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.client.consumer.AckResult; @@ -217,6 +218,11 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen this.clientProcessor.registerConsumerIdsChangeListener(consumerIdsChangeListener); } + @Override + public ConsumerGroupInfo getConsumerGroupInfo(String consumerGroup) { + return this.clientProcessor.getConsumerGroupInfo(consumerGroup); + } + @Override public void addTransactionSubscription(ProxyContext ctx, String producerGroup, String topic) { this.transactionProcessor.addTransactionSubscription(ctx, producerGroup, topic); 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 c01e9c882a..2c957bbf5e 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 @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.client.ClientChannelInfo; +import org.apache.rocketmq.broker.client.ConsumerGroupInfo; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; import org.apache.rocketmq.client.consumer.AckResult; @@ -222,6 +223,8 @@ public interface MessagingProcessor extends StartAndShutdown { ConsumerIdsChangeListener consumerIdsChangeListener ); + ConsumerGroupInfo getConsumerGroupInfo(String consumerGroup); + void addTransactionSubscription( ProxyContext ctx, String producerGroup, From 0a017719c3c55b69cd9f59efbf9b569d5f5eec98 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 9 Jun 2022 17:02:16 +0800 Subject: [PATCH 244/338] [ISSUE #3949] Add topic and queueId for MessageReceiptHandle --- .../proxy/common/MessageReceiptHandle.java | 18 +++++---- .../v2/consumer/ReceiveMessageActivity.java | 4 +- .../processor/ReceiptHandleProcessor.java | 7 ++-- .../processor/ReceiptHandleProcessorTest.java | 39 ++++++++++--------- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java index 4c396e71d0..81fcebd082 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java @@ -17,11 +17,10 @@ package org.apache.rocketmq.proxy.common; -import org.apache.rocketmq.common.message.MessageQueue; - public class MessageReceiptHandle { private final String group; - private final MessageQueue messageQueue; + private final String topic; + private final int queueId; private final String messageId; private final long queueOffset; private final String originalReceiptHandle; @@ -31,10 +30,11 @@ public class MessageReceiptHandle { private String receiptHandle; - public MessageReceiptHandle(String group, MessageQueue messageQueue, String receiptHandle, String messageId, + public MessageReceiptHandle(String group, String topic, int queueId, String receiptHandle, String messageId, long queueOffset, int reconsumeTimes, long expectInvisibleTime) { this.group = group; - this.messageQueue = messageQueue; + this.topic = topic; + this.queueId = queueId; this.receiptHandle = receiptHandle; this.originalReceiptHandle = receiptHandle; this.messageId = messageId; @@ -48,8 +48,12 @@ public class MessageReceiptHandle { return group; } - public MessageQueue getMessageQueue() { - return messageQueue; + public String getTopic() { + return topic; + } + + public int getQueueId() { + return queueId; } public String getReceiptHandle() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 42808961ce..7d0fcaa6fc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -32,7 +32,6 @@ import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; -import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.MessageReceiptHandle; @@ -121,9 +120,8 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { for (MessageExt messageExt : messageExtList) { String receiptHandle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); if (receiptHandle != null) { - MessageQueue messageQueue = new MessageQueue(topic, messageExt.getBrokerName(), messageExt.getQueueId()); MessageReceiptHandle messageReceiptHandle = - new MessageReceiptHandle(group, messageQueue, receiptHandle, messageExt.getMsgId(), + new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); String channelId = proxyContext.getVal(ContextVariable.CHANNEL_KEY); receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 6b2aaca25e..10179a7fa8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -134,7 +134,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { if (current - messageReceiptHandle.getTimestamp() < messageReceiptHandle.getExpectInvisibleTime()) { CompletableFuture future = messagingProcessor.changeInvisibleTime(ProxyContext.create(), handle, messageReceiptHandle.getMessageId(), - messageReceiptHandle.getGroup(), messageReceiptHandle.getMessageQueue().getTopic(), proxyConfig.getRenewSliceTimeMillis()); + messageReceiptHandle.getGroup(), messageReceiptHandle.getTopic(), proxyConfig.getRenewSliceTimeMillis()); future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { messageReceiptHandle.update(ackResult.getExtraInfo()); @@ -144,8 +144,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } else { CompletableFuture future = messagingProcessor.changeInvisibleTime(ProxyContext.create(), handle, messageReceiptHandle.getMessageId(), messageReceiptHandle.getGroup(), - messageReceiptHandle.getMessageQueue().getTopic(), - retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes(), TimeUnit.MILLISECONDS)); + messageReceiptHandle.getTopic(), retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes(), TimeUnit.MILLISECONDS)); future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { removeReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle()); @@ -187,7 +186,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { receiptHandle, value0.getMessageId(), value0.getGroup(), - value0.getMessageQueue().getTopic(), + value0.getTopic(), proxyConfig.getInvisibleTimeMillisWhenClear() ); }); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index 73c05a6784..c8587a8294 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -23,7 +23,6 @@ import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.MessageReceiptHandle; @@ -38,7 +37,9 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { ProxyContext context = ProxyContext.create(); String group = "group"; - MessageQueue messageQueue = new MessageQueue("topic", "broker", 1); + String topic = "topic"; + String brokerName = "broker"; + int queueId = 1; String messageId = "messageId"; long offset = 123L; long invisibleTime = 100000L; @@ -51,8 +52,8 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(invisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(messageQueue.getBrokerName()) - .queueId(messageQueue.getQueueId()) + .brokerName(brokerName) + .queueId(queueId) .offset(offset) .commitLogOffset(0L) .build().encode(); @@ -62,7 +63,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { context.withVal(ContextVariable.CHANNEL_KEY, "channel-id"); receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); Mockito.doNothing().when(messagingProcessor).registerConsumerListener(Mockito.any(ConsumerIdsChangeListener.class)); - messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, receiptHandle, messageId, offset, + messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, reconsumeTimes, invisibleTime); } @@ -74,7 +75,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); } @Test @@ -90,8 +91,8 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(newInvisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(messageQueue.getBrokerName()) - .queueId(messageQueue.getQueueId()) + .brokerName(brokerName) + .queueId(queueId) .offset(offset) .commitLogOffset(0L) .build(); @@ -100,16 +101,16 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { ackResult.setStatus(AckStatus.OK); ackResult.setExtraInfo(newReceiptHandle); Mockito.when(messagingProcessor.changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis()))) + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis()))) .thenReturn(CompletableFuture.completedFuture(ackResult)); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == invisibleTime), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); } @Test @@ -121,12 +122,12 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(newInvisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(messageQueue.getBrokerName()) - .queueId(messageQueue.getQueueId()) + .brokerName(brokerName) + .queueId(queueId) .offset(offset) .commitLogOffset(0L) .build().encode(); - messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, receiptHandle, messageId, offset, + messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, reconsumeTimes, newInvisibleTime); String channelId = context.getVal(ContextVariable.CHANNEL_KEY); receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); @@ -135,7 +136,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes, TimeUnit.MILLISECONDS))); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes, TimeUnit.MILLISECONDS))); } @@ -147,12 +148,12 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(invisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(messageQueue.getBrokerName()) - .queueId(messageQueue.getQueueId()) + .brokerName(brokerName) + .queueId(queueId) .offset(offset) .commitLogOffset(0L) .build().encode(); - messageReceiptHandle = new MessageReceiptHandle(group, messageQueue, newReceiptHandle, messageId, offset, + messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, newReceiptHandle, messageId, offset, reconsumeTimes, invisibleTime); String channelId = context.getVal(ContextVariable.CHANNEL_KEY); receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); @@ -187,6 +188,6 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(messageQueue.getTopic()), Mockito.eq(ConfigurationManager.getProxyConfig().getInvisibleTimeMillisWhenClear())); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getInvisibleTimeMillisWhenClear())); } } \ No newline at end of file From 042febd9f168d718e46577e4095aba448419bced Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 9 Jun 2022 17:37:05 +0800 Subject: [PATCH 245/338] [ISSUE #3949] Refector ReceiptHandleGroup --- .../apache/rocketmq/proxy/common/ReceiptHandleGroup.java | 6 +++--- .../rocketmq/proxy/processor/ReceiptHandleProcessor.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java index 71e23932b3..05a29c8de7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java @@ -28,11 +28,11 @@ public class ReceiptHandleGroup { receiptHandleMap.put(key, value); } - public void remove(String key) { - receiptHandleMap.remove(key); + public MessageReceiptHandle remove(String key) { + return receiptHandleMap.remove(key); } - public Map all() { + public Map immutableMapView() { return ImmutableMap.copyOf(receiptHandleMap); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 10179a7fa8..533b2b375e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -107,7 +107,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { for (Map.Entry entry : receiptHandleGroupMap.entrySet()) { String key = entry.getKey(); ReceiptHandleGroup group = entry.getValue(); - group.all().forEach((k, v) -> { + group.immutableMapView().forEach((k, v) -> { ReceiptHandle handle = ReceiptHandle.decode(v.getReceiptHandle()); long now = System.currentTimeMillis(); if (handle.getNextVisibleTime() - now > proxyConfig.getRenewAheadTimeMillis()) { @@ -178,7 +178,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { - Map all = v.all(); + Map all = v.immutableMapView(); all.forEach((key0, value0) -> { ReceiptHandle receiptHandle = ReceiptHandle.decode(value0.getReceiptHandle()); messagingProcessor.changeInvisibleTime( From eeccd99321fe6cc9ae490fecd734051ead87eeaa Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 10 Jun 2022 11:16:23 +0800 Subject: [PATCH 246/338] [ISSUE #3949] Add port for GrpcServerBuilder --- .../org/apache/rocketmq/proxy/grpc/GrpcServerBuilder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 e380db3439..024766bf48 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 @@ -52,12 +52,11 @@ public class GrpcServerBuilder { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected NettyServerBuilder serverBuilder; - public static GrpcServerBuilder newBuilder(ThreadPoolExecutor executor) { - return new GrpcServerBuilder(executor); + public static GrpcServerBuilder newBuilder(ThreadPoolExecutor executor, int port) { + return new GrpcServerBuilder(executor, port); } - public GrpcServerBuilder(ThreadPoolExecutor executor) { - int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); + protected GrpcServerBuilder(ThreadPoolExecutor executor, int port) { serverBuilder = NettyServerBuilder.forPort(port); try { From 404ee7e8584a3232f93721b7bf2720e5253b3224 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 10 Jun 2022 11:16:23 +0800 Subject: [PATCH 247/338] [ISSUE #3949] Add port for GrpcServerBuilder --- proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3eb3c26850..383a99a5bc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/ProxyStartup.java @@ -66,7 +66,7 @@ public class ProxyStartup { MessagingProcessor messagingProcessor = createMessagingProcessor(); // create grpcServer - GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor) + GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor, ConfigurationManager.getProxyConfig().getGrpcServerPort()) .addService(createServiceProcessor(messagingProcessor)) .configInterceptor() .build(); From 20d6495555f0ef2cfbd7547967ff7753d3a7d376 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 14 Jun 2022 14:39:56 +0800 Subject: [PATCH 248/338] [ISSUE #3949] rename getProxyOutService to getProxyRelayService --- .../rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java | 2 +- .../rocketmq/proxy/processor/DefaultMessagingProcessor.java | 2 +- .../apache/rocketmq/proxy/processor/MessagingProcessor.java | 2 +- .../org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 9ac1001e6d..1052246189 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -71,7 +71,7 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { GrpcClientSettingsManager grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); - GrpcChannelManager grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); + GrpcChannelManager grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyRelayService()); ReceiptHandleProcessor receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); 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 5e5ce2e39b..773b2f3ae0 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 @@ -229,7 +229,7 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public ProxyRelayService getProxyOutService() { + public ProxyRelayService getProxyRelayService() { return this.serviceManager.getProxyRelayService(); } 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 2c957bbf5e..02c28fa53e 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 @@ -231,7 +231,7 @@ public interface MessagingProcessor extends StartAndShutdown { String topic ); - ProxyRelayService getProxyOutService(); + ProxyRelayService getProxyRelayService(); MetadataService getMetadataService(); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index 86ecf5da57..51ff93a5e8 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -65,8 +65,8 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); - when(messagingProcessor.getProxyOutService()).thenReturn(proxyRelayService); - grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyOutService()); + when(messagingProcessor.getProxyRelayService()).thenReturn(proxyRelayService); + grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyRelayService()); } protected Context createContext() { From 33f422a2055894e528a451afa83d5310dc1d67d6 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 14 Jun 2022 19:27:27 +0800 Subject: [PATCH 249/338] [ISSUE #3949] Add method for MessagingProcessor and MessageService * Add pullMessage, updateConsumerOffset, lockBatchMQ and unlockBatchMQ --- .../proxy/processor/ConsumerProcessor.java | 116 ++++++++++++++++++ .../processor/DefaultMessagingProcessor.java | 29 +++++ .../proxy/processor/MessagingProcessor.java | 40 ++++++ .../message/ClusterMessageService.java | 48 +++++++- .../service/message/LocalMessageService.java | 31 +++++ .../proxy/service/message/MessageService.java | 35 ++++++ .../service/mqclient/MQClientAPIExt.java | 97 +++++++++++---- .../ClusterTransactionService.java | 11 +- .../service/mqclient/MQClientAPIExtTest.java | 13 +- 9 files changed, 388 insertions(+), 32 deletions(-) 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 8dfe714200..366f85a85e 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 @@ -18,18 +18,29 @@ package org.apache.rocketmq.proxy.processor; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; +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.PopStatus; +import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -202,4 +213,109 @@ public class ConsumerProcessor extends AbstractProcessor { } return FutureUtils.addExecutor(future, this.executor); } + + public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + String consumerGroup, long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, + long suspendTimeoutMillis, SubscriptionData subscriptionData, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(selectableMessageQueue.getTopic()); + requestHeader.setQueueId(selectableMessageQueue.getQueueId()); + requestHeader.setQueueOffset(queueOffset); + requestHeader.setMaxMsgNums(maxMsgNums); + requestHeader.setSysFlag(sysFlag); + requestHeader.setCommitOffset(commitOffset); + requestHeader.setSuspendTimeoutMillis(suspendTimeoutMillis); + requestHeader.setSubscription(subscriptionData.getSubString()); + requestHeader.setExpressionType(subscriptionData.getExpressionType()); + try { + future = serviceManager.getMessageService().pullMessage(ctx, selectableMessageQueue, requestHeader, timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return FutureUtils.addExecutor(future, this.executor); + } + + public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + String consumerGroup, long commitOffset, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(selectableMessageQueue.getTopic()); + requestHeader.setQueueId(selectableMessageQueue.getQueueId()); + requestHeader.setCommitOffset(commitOffset); + try { + future = serviceManager.getMessageService().updateConsumerOffset(ctx, selectableMessageQueue, requestHeader, timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return FutureUtils.addExecutor(future, this.executor); + } + + public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, + String consumerGroup, String clientId, long timeoutMillis) { + CompletableFuture> future = new CompletableFuture<>(); + Set successSet = new CopyOnWriteArraySet<>(); + Map> messageQueueSetMap = buildMapByBrokerName(mqSet); + List>> futureList = new ArrayList<>(); + messageQueueSetMap.forEach((k, v) -> { + LockBatchRequestBody requestBody = new LockBatchRequestBody(); + requestBody.setConsumerGroup(consumerGroup); + requestBody.setClientId(clientId); + requestBody.setMqSet(v.stream().map(SelectableMessageQueue::getMessageQueue).collect(Collectors.toSet())); + CompletableFuture> future0 = new CompletableFuture<>(); + try { + future0 = serviceManager.getMessageService().lockBatchMQ(ctx, v.get(0), requestBody, timeoutMillis); + future0.thenAccept(successSet::addAll); + } catch (Throwable t) { + future0.completeExceptionally(t); + } + futureList.add(FutureUtils.addExecutor(future0, this.executor)); + }); + CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).whenComplete((v, t) -> { + if (t != null) { + log.error("LockBatchMQ failed", t); + } + future.complete(successSet); + }); + return FutureUtils.addExecutor(future, this.executor); + } + + public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, + String clientId, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + Map> messageQueueSetMap = buildMapByBrokerName(mqSet); + List> futureList = new ArrayList<>(); + messageQueueSetMap.forEach((k, v) -> { + UnlockBatchRequestBody requestBody = new UnlockBatchRequestBody(); + requestBody.setConsumerGroup(consumerGroup); + requestBody.setClientId(clientId); + requestBody.setMqSet(v.stream().map(SelectableMessageQueue::getMessageQueue).collect(Collectors.toSet())); + CompletableFuture future0 = new CompletableFuture<>(); + try { + future0 = serviceManager.getMessageService().unlockBatchMQ(ctx, v.get(0), requestBody, timeoutMillis); + future0.complete(null); + } catch (Throwable t) { + future0.completeExceptionally(t); + } + futureList.add(FutureUtils.addExecutor(future0, this.executor)); + }); + CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).whenComplete((v, t) -> { + if (t != null) { + log.error("UnlockBatchMQ failed", t); + } + future.complete(null); + }); + return FutureUtils.addExecutor(future, this.executor); + } + + public HashMap> buildMapByBrokerName(final Set mqSet) { + HashMap> result = new HashMap<>(); + for (SelectableMessageQueue mq : mqSet) { + List mqs = result.computeIfAbsent(mq.getBrokerName(), k -> new ArrayList<>()); + mqs.add(mq); + } + return result; + } } 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 773b2f3ae0..98aef3129e 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 @@ -29,11 +29,13 @@ import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; @@ -49,6 +51,7 @@ import org.apache.rocketmq.proxy.service.ServiceManagerFactory; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; @@ -176,6 +179,32 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen return this.consumerProcessor.changeInvisibleTime(ctx, handle, messageId, groupName, topicName, invisibleTime, timeoutMillis); } + @Override + public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + String consumerGroup, long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, + long suspendTimeoutMillis, SubscriptionData subscriptionData, long timeoutMillis) { + return this.consumerProcessor.pullMessage(ctx, selectableMessageQueue, consumerGroup, queueOffset, maxMsgNums, + sysFlag, commitOffset, suspendTimeoutMillis, subscriptionData, timeoutMillis); + } + + @Override + public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + String consumerGroup, long commitOffset, long timeoutMillis) { + return this.consumerProcessor.updateConsumerOffset(ctx, selectableMessageQueue, consumerGroup, commitOffset, timeoutMillis); + } + + @Override + public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, + String consumerGroup, String clientId, long timeoutMillis) { + return this.consumerProcessor.lockBatchMQ(ctx, mqSet, consumerGroup, clientId, timeoutMillis); + } + + @Override + public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, + String clientId, long timeoutMillis) { + return this.consumerProcessor.unlockBatchMQ(ctx, mqSet, consumerGroup, clientId, timeoutMillis); + } + @Override public void registerProducer(ProxyContext ctx, String producerGroup, ClientChannelInfo clientChannelInfo) { this.clientProcessor.registerProducer(ctx, producerGroup, clientChannelInfo); 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 02c28fa53e..caf98a438a 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 @@ -27,11 +27,13 @@ import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.broker.client.ProducerChangeListener; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; @@ -42,6 +44,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; +import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -175,6 +178,43 @@ public interface MessagingProcessor extends StartAndShutdown { long timeoutMillis ); + CompletableFuture pullMessage( + ProxyContext ctx, + SelectableMessageQueue selectableMessageQueue, + String consumerGroup, + long queueOffset, + int maxMsgNums, + int sysFlag, + long commitOffset, + long suspendTimeoutMillis, + SubscriptionData subscriptionData, + long timeoutMillis + ); + + CompletableFuture updateConsumerOffset( + ProxyContext ctx, + SelectableMessageQueue selectableMessageQueue, + String consumerGroup, + long commitOffset, + long timeoutMillis + ); + + CompletableFuture> lockBatchMQ( + ProxyContext ctx, + Set mqSet, + String consumerGroup, + String clientId, + long timeoutMillis + ); + + CompletableFuture unlockBatchMQ( + ProxyContext ctx, + Set mqSet, + String consumerGroup, + String clientId, + long timeoutMillis + ); + void registerProducer( ProxyContext ctx, String producerGroup, 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 15e3af47ca..a3b84599c2 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 @@ -18,19 +18,26 @@ package org.apache.rocketmq.proxy.service.message; import com.google.common.collect.Lists; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; @@ -42,7 +49,6 @@ import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ClusterMessageService implements MessageService { - private final TopicRouteService topicRouteService; private final MQClientAPIFactory mqClientAPIFactory; @@ -123,6 +129,46 @@ public class ClusterMessageService implements MessageService { ); } + @Override + public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + PullMessageRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().pullMessageAsync( + messageQueue.getBrokerAddr(), + requestHeader, + timeoutMillis + ); + } + + @Override + public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue messageQueue, + UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().updateConsumerOffsetOneWay( + messageQueue.getBrokerAddr(), + requestHeader, + timeoutMillis + ); + } + + @Override + public CompletableFuture> lockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + LockBatchRequestBody requestBody, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().lockBatchMQWithFuture( + messageQueue.getBrokerAddr(), + requestBody, + timeoutMillis + ); + } + + @Override + public CompletableFuture unlockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + UnlockBatchRequestBody requestBody, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().unlockBatchMQOneway( + messageQueue.getBrokerAddr(), + requestBody, + timeoutMillis + ); + } + protected String resolveBrokerAddr(ReceiptHandle handle) { return resolveBrokerAddr(handle.getBrokerName()); } 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 ac4b4079be..07482ec968 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 @@ -23,12 +23,15 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.NotImplementedException; import org.apache.rocketmq.broker.BrokerController; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; +import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.constant.LoggerName; @@ -42,6 +45,8 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHeader; @@ -50,8 +55,10 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; @@ -343,4 +350,28 @@ public class LocalMessageService implements MessageService { return ackResult; }); } + + @Override + public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + PullMessageRequestHeader requestHeader, long timeoutMillis) { + throw new NotImplementedException("pullMessage is not implemented in LocalMessageService"); + } + + @Override + public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue messageQueue, + UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { + throw new NotImplementedException("updateConsumerOffset is not implemented in LocalMessageService"); + } + + @Override + public CompletableFuture> lockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + LockBatchRequestBody requestBody, long timeoutMillis) { + throw new NotImplementedException("lockBatchMQ is not implemented in LocalMessageService"); + } + + @Override + public CompletableFuture unlockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + UnlockBatchRequestBody requestBody, long timeoutMillis) { + throw new NotImplementedException("unlockBatchMQ is not implemented in LocalMessageService"); + } } 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 7c2d2ea9e5..768ab5f19b 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 @@ -17,19 +17,26 @@ package org.apache.rocketmq.proxy.service.message; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageQueue; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -83,4 +90,32 @@ public interface MessageService { AckMessageRequestHeader requestHeader, long timeoutMillis ); + + CompletableFuture pullMessage( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + PullMessageRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture updateConsumerOffset( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + UpdateConsumerOffsetRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture> lockBatchMQ( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + LockBatchRequestBody requestBody, + long timeoutMillis + ); + + CompletableFuture unlockBatchMQ( + ProxyContext ctx, + SelectableMessageQueue messageQueue, + UnlockBatchRequestBody requestBody, + long timeoutMillis + ); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 1af6f3acb7..5380f540ba 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -19,6 +19,7 @@ package org.apache.rocketmq.proxy.service.mqclient; import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.consumer.AckCallback; @@ -41,8 +42,12 @@ import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; +import org.apache.rocketmq.common.protocol.body.LockBatchResponseBody; +import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; @@ -60,11 +65,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.remoting.exception.RemotingConnectException; -import org.apache.rocketmq.remoting.exception.RemotingException; -import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; -import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; -import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -106,15 +106,22 @@ public class MQClientAPIExt extends MQClientAPIImpl { return ex; } - public void sendHeartbeatOneway( + public CompletableFuture sendHeartbeatOneway( String brokerAddr, HeartbeatData heartbeatData, long timeoutMillis - ) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, RemotingTooMuchRequestException { - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); - request.setLanguage(clientConfig.getLanguage()); - request.setBody(heartbeatData.encode()); - this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + ) { + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null); + request.setLanguage(clientConfig.getLanguage()); + request.setBody(heartbeatData.encode()); + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + future.complete(null); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; } public CompletableFuture sendHeartbeatAsync( @@ -349,13 +356,20 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public void updateConsumerOffsetOneWay( + public CompletableFuture updateConsumerOffsetOneWay( String brokerAddr, UpdateConsumerOffsetRequestHeader header, long timeoutMillis - ) throws InterruptedException, RemotingException { - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONSUMER_OFFSET, header); - this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + ) { + CompletableFuture future = new CompletableFuture<>(); + try { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONSUMER_OFFSET, header); + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + future.complete(null); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; } public CompletableFuture> getConsumerListByGroupAsync( @@ -401,10 +415,7 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public CompletableFuture getMaxOffsetAsync(String brokerAddr, String topic, int queueId, long timeoutMillis) { - GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); + public CompletableFuture getMaxOffset(String brokerAddr, GetMaxOffsetRequestHeader requestHeader, long timeoutMillis) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); CompletableFuture future = new CompletableFuture<>(); @@ -431,12 +442,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public CompletableFuture searchOffsetAsync(String brokerAddr, String topic, int queueId, long timestamp, + public CompletableFuture searchOffset(String brokerAddr, SearchOffsetRequestHeader requestHeader, long timeoutMillis) { - SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); - requestHeader.setTimestamp(timestamp); RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); CompletableFuture future = new CompletableFuture<>(); @@ -463,4 +470,46 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } + 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)); + } + }); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } + + public CompletableFuture unlockBatchMQOneway(String brokerAddr, + UnlockBatchRequestBody requestBody, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UNLOCK_BATCH_MQ, null); + request.setBody(requestBody.encode()); + try { + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + future.complete(null); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index 93966d4f79..fd0943f657 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -195,11 +195,12 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS for (BrokerData brokerData : brokerDataList) { heartbeatExecutors.submit(() -> { String brokerAddr = brokerData.selectBrokerAddr(); - try { - this.mqClientAPIFactory.getClient().sendHeartbeatOneway(brokerAddr, heartbeatData, Duration.ofSeconds(3).toMillis()); - } catch (Exception e) { - log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, e); - } + this.mqClientAPIFactory.getClient() + .sendHeartbeatOneway(brokerAddr, heartbeatData, Duration.ofSeconds(3).toMillis()) + .exceptionally(t -> { + log.error("Send transactionHeartbeat to broker err. brokerAddr: {}", brokerAddr, t); + return null; + }); }); } } catch (Exception e) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java index db3ef7bf8d..fad425420d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExtTest.java @@ -51,9 +51,11 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.GetMaxOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SearchOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; @@ -310,7 +312,10 @@ public class MQClientAPIExtTest { return null; }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); - assertEquals(offset, mqClientAPI.getMaxOffsetAsync(BROKER_ADDR, TOPIC, 0, TIMEOUT).get().longValue()); + GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); + requestHeader.setTopic(TOPIC); + requestHeader.setQueueId(0); + assertEquals(offset, mqClientAPI.getMaxOffset(BROKER_ADDR, requestHeader, TIMEOUT).get().longValue()); } @Test @@ -329,7 +334,11 @@ public class MQClientAPIExtTest { return null; }).when(remotingClient).invokeAsync(anyString(), any(RemotingCommand.class), anyLong(), any()); - assertEquals(offset, mqClientAPI.searchOffsetAsync(BROKER_ADDR, TOPIC, 0, System.currentTimeMillis(), TIMEOUT).get().longValue()); + SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); + requestHeader.setTopic(TOPIC); + requestHeader.setQueueId(0); + requestHeader.setTimestamp(System.currentTimeMillis()); + assertEquals(offset, mqClientAPI.searchOffset(BROKER_ADDR, requestHeader, TIMEOUT).get().longValue()); } protected MessageExt createMessage() { From 03d2f9b4c231f3ed7fcb2f3f453794081ed15608 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 15 Jun 2022 19:20:24 +0800 Subject: [PATCH 250/338] [ISSUE #3949] Rename to AddressableMessageQueue --- .../v2/consumer/ReceiveMessageActivity.java | 14 ++-- .../grpc/v2/producer/SendMessageActivity.java | 8 +- .../proxy/processor/ConsumerProcessor.java | 84 +++++++++++-------- .../processor/DefaultMessagingProcessor.java | 18 ++-- .../proxy/processor/MessagingProcessor.java | 9 +- .../proxy/processor/ProducerProcessor.java | 4 +- .../proxy/processor/QueueSelector.java | 4 +- .../message/ClusterMessageService.java | 14 ++-- .../service/message/LocalMessageService.java | 14 ++-- .../proxy/service/message/MessageService.java | 14 ++-- ...ueue.java => AddressableMessageQueue.java} | 10 +-- .../route/ClusterTopicRouteService.java | 7 ++ .../service/route/LocalTopicRouteService.java | 7 ++ .../service/route/MessageQueueSelector.java | 36 ++++---- .../service/route/TopicRouteService.java | 3 + .../consumer/ReceiveMessageActivityTest.java | 8 +- .../v2/producer/SendMessageActivityTest.java | 8 +- .../processor/ConsumerProcessorTest.java | 6 +- .../processor/ProducerProcessorTest.java | 6 +- .../message/LocalMessageServiceTest.java | 4 +- .../route/MessageQueueSelectorTest.java | 12 +-- 21 files changed, 162 insertions(+), 128 deletions(-) rename proxy/src/main/java/org/apache/rocketmq/proxy/service/route/{SelectableMessageQueue.java => AddressableMessageQueue.java} (86%) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 7d0fcaa6fc..1b8087b20c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -47,7 +47,7 @@ import org.apache.rocketmq.proxy.processor.QueueSelector; import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; import org.apache.rocketmq.proxy.service.route.MessageQueueSelector; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; public class ReceiveMessageActivity extends AbstractMessingActivity { protected ReceiptHandleProcessor receiptHandleProcessor; @@ -156,19 +156,19 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { } @Override - public SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { + public AddressableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { try { - SelectableMessageQueue selectableMessageQueue = null; + AddressableMessageQueue addressableMessageQueue = null; MessageQueueSelector messageQueueSelector = messageQueueView.getReadSelector(); if (StringUtils.isNotBlank(brokerName)) { - selectableMessageQueue = messageQueueSelector.getQueueByBrokerName(brokerName); + addressableMessageQueue = messageQueueSelector.getQueueByBrokerName(brokerName); } - if (selectableMessageQueue == null) { - selectableMessageQueue = messageQueueSelector.selectOne(true); + if (addressableMessageQueue == null) { + addressableMessageQueue = messageQueueSelector.selectOne(true); } - return selectableMessageQueue; + return addressableMessageQueue; } catch (Throwable t) { return null; } 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 5435900416..adcb364566 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 @@ -52,7 +52,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; public class SendMessageActivity extends AbstractMessingActivity { @@ -252,17 +252,17 @@ public class SendMessageActivity extends AbstractMessingActivity { } @Override - public SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { + public AddressableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView) { try { apache.rocketmq.v2.Message message = request.getMessages(0); String shardingKey = null; if (request.getMessagesCount() == 1) { shardingKey = message.getSystemProperties().getMessageGroup(); } - SelectableMessageQueue targetMessageQueue; + AddressableMessageQueue targetMessageQueue; if (StringUtils.isNotEmpty(shardingKey)) { // With shardingKey - List writeQueues = messageQueueView.getWriteSelector().getQueues(); + List writeQueues = messageQueueView.getWriteSelector().getQueues(); int bucket = Hashing.consistentHash(shardingKey.hashCode(), writeQueues.size()); targetMessageQueue = writeQueues.get(bucket); } else { 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 366f85a85e..596dbc1b34 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 @@ -50,7 +50,7 @@ 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.ServiceManager; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; public class ConsumerProcessor extends AbstractProcessor { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -79,7 +79,7 @@ public class ConsumerProcessor extends AbstractProcessor { ) { CompletableFuture future = new CompletableFuture<>(); try { - SelectableMessageQueue messageQueue = queueSelector.select(ctx, this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); + AddressableMessageQueue messageQueue = queueSelector.select(ctx, this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); if (messageQueue == null) { throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no readable queue"); } @@ -214,56 +214,61 @@ public class ConsumerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } - public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, - String consumerGroup, long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, + public CompletableFuture pullMessage(ProxyContext ctx, MessageQueue messageQueue, String consumerGroup, + long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, long suspendTimeoutMillis, SubscriptionData subscriptionData, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); - PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); - requestHeader.setConsumerGroup(consumerGroup); - requestHeader.setTopic(selectableMessageQueue.getTopic()); - requestHeader.setQueueId(selectableMessageQueue.getQueueId()); - requestHeader.setQueueOffset(queueOffset); - requestHeader.setMaxMsgNums(maxMsgNums); - requestHeader.setSysFlag(sysFlag); - requestHeader.setCommitOffset(commitOffset); - requestHeader.setSuspendTimeoutMillis(suspendTimeoutMillis); - requestHeader.setSubscription(subscriptionData.getSubString()); - requestHeader.setExpressionType(subscriptionData.getExpressionType()); try { - future = serviceManager.getMessageService().pullMessage(ctx, selectableMessageQueue, requestHeader, timeoutMillis); + AddressableMessageQueue addressableMessageQueue = serviceManager.getTopicRouteService() + .buildAddressableMessageQueue(messageQueue); + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(addressableMessageQueue.getTopic()); + requestHeader.setQueueId(addressableMessageQueue.getQueueId()); + requestHeader.setQueueOffset(queueOffset); + requestHeader.setMaxMsgNums(maxMsgNums); + requestHeader.setSysFlag(sysFlag); + requestHeader.setCommitOffset(commitOffset); + requestHeader.setSuspendTimeoutMillis(suspendTimeoutMillis); + requestHeader.setSubscription(subscriptionData.getSubString()); + requestHeader.setExpressionType(subscriptionData.getExpressionType()); + future = serviceManager.getMessageService().pullMessage(ctx, addressableMessageQueue, requestHeader, timeoutMillis); } catch (Throwable t) { future.completeExceptionally(t); } return FutureUtils.addExecutor(future, this.executor); } - public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + public CompletableFuture updateConsumerOffset(ProxyContext ctx, MessageQueue messageQueue, String consumerGroup, long commitOffset, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); - UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader(); - requestHeader.setConsumerGroup(consumerGroup); - requestHeader.setTopic(selectableMessageQueue.getTopic()); - requestHeader.setQueueId(selectableMessageQueue.getQueueId()); - requestHeader.setCommitOffset(commitOffset); try { - future = serviceManager.getMessageService().updateConsumerOffset(ctx, selectableMessageQueue, requestHeader, timeoutMillis); + AddressableMessageQueue addressableMessageQueue = serviceManager.getTopicRouteService() + .buildAddressableMessageQueue(messageQueue); + UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(addressableMessageQueue.getTopic()); + requestHeader.setQueueId(addressableMessageQueue.getQueueId()); + requestHeader.setCommitOffset(commitOffset); + future = serviceManager.getMessageService().updateConsumerOffset(ctx, addressableMessageQueue, requestHeader, timeoutMillis); } catch (Throwable t) { future.completeExceptionally(t); } return FutureUtils.addExecutor(future, this.executor); } - public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, + public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, String clientId, long timeoutMillis) { CompletableFuture> future = new CompletableFuture<>(); Set successSet = new CopyOnWriteArraySet<>(); - Map> messageQueueSetMap = buildMapByBrokerName(mqSet); + Set addressableMessageQueueSet = buildAddressableSet(mqSet); + Map> messageQueueSetMap = buildAddressableMapByBrokerName(addressableMessageQueueSet); List>> futureList = new ArrayList<>(); messageQueueSetMap.forEach((k, v) -> { LockBatchRequestBody requestBody = new LockBatchRequestBody(); requestBody.setConsumerGroup(consumerGroup); requestBody.setClientId(clientId); - requestBody.setMqSet(v.stream().map(SelectableMessageQueue::getMessageQueue).collect(Collectors.toSet())); + requestBody.setMqSet(v.stream().map(AddressableMessageQueue::getMessageQueue).collect(Collectors.toSet())); CompletableFuture> future0 = new CompletableFuture<>(); try { future0 = serviceManager.getMessageService().lockBatchMQ(ctx, v.get(0), requestBody, timeoutMillis); @@ -282,16 +287,18 @@ public class ConsumerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } - public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, + public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, + String consumerGroup, String clientId, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); - Map> messageQueueSetMap = buildMapByBrokerName(mqSet); + Set addressableMessageQueueSet = buildAddressableSet(mqSet); + Map> messageQueueSetMap = buildAddressableMapByBrokerName(addressableMessageQueueSet); List> futureList = new ArrayList<>(); messageQueueSetMap.forEach((k, v) -> { UnlockBatchRequestBody requestBody = new UnlockBatchRequestBody(); requestBody.setConsumerGroup(consumerGroup); requestBody.setClientId(clientId); - requestBody.setMqSet(v.stream().map(SelectableMessageQueue::getMessageQueue).collect(Collectors.toSet())); + requestBody.setMqSet(v.stream().map(AddressableMessageQueue::getMessageQueue).collect(Collectors.toSet())); CompletableFuture future0 = new CompletableFuture<>(); try { future0 = serviceManager.getMessageService().unlockBatchMQ(ctx, v.get(0), requestBody, timeoutMillis); @@ -310,10 +317,21 @@ public class ConsumerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } - public HashMap> buildMapByBrokerName(final Set mqSet) { - HashMap> result = new HashMap<>(); - for (SelectableMessageQueue mq : mqSet) { - List mqs = result.computeIfAbsent(mq.getBrokerName(), k -> new ArrayList<>()); + protected Set buildAddressableSet(Set mqSet) { + return mqSet.stream().map(mq -> { + try { + return serviceManager.getTopicRouteService().buildAddressableMessageQueue(mq); + } catch (Exception e) { + return null; + } + }).collect(Collectors.toSet()); + } + + protected HashMap> buildAddressableMapByBrokerName( + final Set mqSet) { + HashMap> result = new HashMap<>(); + for (AddressableMessageQueue mq : mqSet) { + List mqs = result.computeIfAbsent(mq.getBrokerName(), k -> new ArrayList<>()); mqs.add(mq); } return result; 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 98aef3129e..813a6b7527 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 @@ -51,7 +51,6 @@ import org.apache.rocketmq.proxy.service.ServiceManagerFactory; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; @@ -180,27 +179,28 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, - String consumerGroup, long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, - long suspendTimeoutMillis, SubscriptionData subscriptionData, long timeoutMillis) { - return this.consumerProcessor.pullMessage(ctx, selectableMessageQueue, consumerGroup, queueOffset, maxMsgNums, + public CompletableFuture pullMessage(ProxyContext ctx, MessageQueue messageQueue, String consumerGroup, + long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, long suspendTimeoutMillis, + SubscriptionData subscriptionData, long timeoutMillis) { + return this.consumerProcessor.pullMessage(ctx, messageQueue, consumerGroup, queueOffset, maxMsgNums, sysFlag, commitOffset, suspendTimeoutMillis, subscriptionData, timeoutMillis); } @Override - public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue selectableMessageQueue, + public CompletableFuture updateConsumerOffset(ProxyContext ctx, MessageQueue messageQueue, String consumerGroup, long commitOffset, long timeoutMillis) { - return this.consumerProcessor.updateConsumerOffset(ctx, selectableMessageQueue, consumerGroup, commitOffset, timeoutMillis); + return this.consumerProcessor.updateConsumerOffset(ctx, messageQueue, consumerGroup, commitOffset, timeoutMillis); } @Override - public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, + public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, String clientId, long timeoutMillis) { return this.consumerProcessor.lockBatchMQ(ctx, mqSet, consumerGroup, clientId, timeoutMillis); } @Override - public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, + public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, + String consumerGroup, String clientId, long timeoutMillis) { return this.consumerProcessor.unlockBatchMQ(ctx, mqSet, consumerGroup, clientId, 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 caf98a438a..5ecdb65727 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 @@ -44,7 +44,6 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -180,7 +179,7 @@ public interface MessagingProcessor extends StartAndShutdown { CompletableFuture pullMessage( ProxyContext ctx, - SelectableMessageQueue selectableMessageQueue, + MessageQueue messageQueue, String consumerGroup, long queueOffset, int maxMsgNums, @@ -193,7 +192,7 @@ public interface MessagingProcessor extends StartAndShutdown { CompletableFuture updateConsumerOffset( ProxyContext ctx, - SelectableMessageQueue selectableMessageQueue, + MessageQueue messageQueue, String consumerGroup, long commitOffset, long timeoutMillis @@ -201,7 +200,7 @@ public interface MessagingProcessor extends StartAndShutdown { CompletableFuture> lockBatchMQ( ProxyContext ctx, - Set mqSet, + Set mqSet, String consumerGroup, String clientId, long timeoutMillis @@ -209,7 +208,7 @@ public interface MessagingProcessor extends StartAndShutdown { CompletableFuture unlockBatchMQ( ProxyContext ctx, - Set mqSet, + Set mqSet, String consumerGroup, String clientId, long timeoutMillis 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 f6c9e71298..7586c9b401 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 @@ -42,7 +42,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.processor.validator.DefaultTopicMessageTypeValidator; import org.apache.rocketmq.proxy.processor.validator.TopicMessageTypeValidator; import org.apache.rocketmq.proxy.service.ServiceManager; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -74,7 +74,7 @@ public class ProducerProcessor extends AbstractProcessor { } } } - SelectableMessageQueue messageQueue = queueSelector.select(ctx, + AddressableMessageQueue messageQueue = queueSelector.select(ctx, this.serviceManager.getTopicRouteService().getCurrentMessageQueueView(topic)); if (messageQueue == null) { throw new ProxyException(ProxyExceptionCode.FORBIDDEN, "no writable queue"); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java index ae6d66d9bb..f6a7f21b32 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java @@ -18,9 +18,9 @@ package org.apache.rocketmq.proxy.processor; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; public interface QueueSelector { - SelectableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView); + AddressableMessageQueue select(ProxyContext ctx, MessageQueueView messageQueueView); } 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 a3b84599c2..e4b92d8591 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 @@ -42,7 +42,7 @@ 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.service.mqclient.MQClientAPIFactory; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; @@ -58,7 +58,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture> sendMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { CompletableFuture> future; if (msgList.size() == 1) { @@ -98,7 +98,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture popMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis) { return this.mqClientAPIFactory.getClient().popMessageAsync( messageQueue.getBrokerAddr(), @@ -130,7 +130,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture pullMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, PullMessageRequestHeader requestHeader, long timeoutMillis) { return this.mqClientAPIFactory.getClient().pullMessageAsync( messageQueue.getBrokerAddr(), @@ -140,7 +140,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture updateConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { return this.mqClientAPIFactory.getClient().updateConsumerOffsetOneWay( messageQueue.getBrokerAddr(), @@ -150,7 +150,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture> lockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture> lockBatchMQ(ProxyContext ctx, AddressableMessageQueue messageQueue, LockBatchRequestBody requestBody, long timeoutMillis) { return this.mqClientAPIFactory.getClient().lockBatchMQWithFuture( messageQueue.getBrokerAddr(), @@ -160,7 +160,7 @@ public class ClusterMessageService implements MessageService { } @Override - public CompletableFuture unlockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture unlockBatchMQ(ProxyContext ctx, AddressableMessageQueue messageQueue, UnlockBatchRequestBody requestBody, long timeoutMillis) { return this.mqClientAPIFactory.getClient().unlockBatchMQOneway( messageQueue.getBrokerAddr(), 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 07482ec968..3bf121b8dc 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 @@ -65,7 +65,7 @@ import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.channel.ChannelManager; import org.apache.rocketmq.proxy.service.channel.InvocationContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -83,7 +83,7 @@ public class LocalMessageService implements MessageService { } @Override - public CompletableFuture> sendMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture> sendMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis) { byte[] body; String messageId; @@ -185,7 +185,7 @@ public class LocalMessageService implements MessageService { } @Override - public CompletableFuture popMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture popMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis) { RemotingCommand request = LocalRemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); CompletableFuture future = new CompletableFuture<>(); @@ -352,25 +352,25 @@ public class LocalMessageService implements MessageService { } @Override - public CompletableFuture pullMessage(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture pullMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, PullMessageRequestHeader requestHeader, long timeoutMillis) { throw new NotImplementedException("pullMessage is not implemented in LocalMessageService"); } @Override - public CompletableFuture updateConsumerOffset(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture updateConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { throw new NotImplementedException("updateConsumerOffset is not implemented in LocalMessageService"); } @Override - public CompletableFuture> lockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture> lockBatchMQ(ProxyContext ctx, AddressableMessageQueue messageQueue, LockBatchRequestBody requestBody, long timeoutMillis) { throw new NotImplementedException("lockBatchMQ is not implemented in LocalMessageService"); } @Override - public CompletableFuture unlockBatchMQ(ProxyContext ctx, SelectableMessageQueue messageQueue, + public CompletableFuture unlockBatchMQ(ProxyContext ctx, AddressableMessageQueue messageQueue, UnlockBatchRequestBody requestBody, long timeoutMillis) { throw new NotImplementedException("unlockBatchMQ is not implemented in LocalMessageService"); } 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 768ab5f19b..bdef99c2c3 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 @@ -38,7 +38,7 @@ import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -47,7 +47,7 @@ public interface MessageService { CompletableFuture> sendMessage( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, List msgList, SendMessageRequestHeader requestHeader, long timeoutMillis @@ -70,7 +70,7 @@ public interface MessageService { CompletableFuture popMessage( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis ); @@ -93,28 +93,28 @@ public interface MessageService { CompletableFuture pullMessage( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, PullMessageRequestHeader requestHeader, long timeoutMillis ); CompletableFuture updateConsumerOffset( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis ); CompletableFuture> lockBatchMQ( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, LockBatchRequestBody requestBody, long timeoutMillis ); CompletableFuture unlockBatchMQ( ProxyContext ctx, - SelectableMessageQueue messageQueue, + AddressableMessageQueue messageQueue, UnlockBatchRequestBody requestBody, long timeoutMillis ); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/AddressableMessageQueue.java similarity index 86% rename from proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java rename to proxy/src/main/java/org/apache/rocketmq/proxy/service/route/AddressableMessageQueue.java index 99eccbedfc..ca877f3278 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/SelectableMessageQueue.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/route/AddressableMessageQueue.java @@ -20,18 +20,18 @@ import com.google.common.base.MoreObjects; import java.util.Objects; import org.apache.rocketmq.common.message.MessageQueue; -public class SelectableMessageQueue implements Comparable { +public class AddressableMessageQueue implements Comparable { private final MessageQueue messageQueue; private final String brokerAddr; - public SelectableMessageQueue(MessageQueue messageQueue, String brokerAddr) { + public AddressableMessageQueue(MessageQueue messageQueue, String brokerAddr) { this.messageQueue = messageQueue; this.brokerAddr = brokerAddr; } @Override - public int compareTo(SelectableMessageQueue o) { + public int compareTo(AddressableMessageQueue o) { return messageQueue.compareTo(o.messageQueue); } @@ -40,10 +40,10 @@ public class SelectableMessageQueue implements Comparable queues = new ArrayList<>(); + private final List queues = new ArrayList<>(); // one queue for brokers with queueId : -1 - private final List brokerActingQueues = new ArrayList<>(); - private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); + private final List brokerActingQueues = new ArrayList<>(); + private final Map brokerNameQueueMap = new ConcurrentHashMap<>(); private final AtomicInteger queueIndex; private final AtomicInteger brokerIndex; @@ -56,8 +56,8 @@ public class MessageQueueSelector { this.brokerIndex = new AtomicInteger(Math.abs(new Random().nextInt())); } - private static List buildRead(TopicRouteWrapper topicRoute) { - Set queueSet = new HashSet<>(); + private static List buildRead(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); List qds = topicRoute.getQueueDatas(); if (qds == null) { return new ArrayList<>(); @@ -71,7 +71,7 @@ public class MessageQueueSelector { } for (int i = 0; i < qd.getReadQueueNums(); i++) { - SelectableMessageQueue mq = new SelectableMessageQueue( + AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), brokerAddr); queueSet.add(mq); @@ -82,8 +82,8 @@ public class MessageQueueSelector { return queueSet.stream().sorted().collect(Collectors.toList()); } - private static List buildWrite(TopicRouteWrapper topicRoute) { - Set queueSet = new HashSet<>(); + private static List buildWrite(TopicRouteWrapper topicRoute) { + Set queueSet = new HashSet<>(); // order topic route. if (StringUtils.isNotBlank(topicRoute.getOrderTopicConf())) { String[] brokers = topicRoute.getOrderTopicConf().split(";"); @@ -97,7 +97,7 @@ public class MessageQueueSelector { int nums = Integer.parseInt(item[1]); for (int i = 0; i < nums; i++) { - SelectableMessageQueue mq = new SelectableMessageQueue( + AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), brokerName, i), brokerAddr); queueSet.add(mq); @@ -117,7 +117,7 @@ public class MessageQueueSelector { } for (int i = 0; i < qd.getWriteQueueNums(); i++) { - SelectableMessageQueue mq = new SelectableMessageQueue( + AddressableMessageQueue mq = new AddressableMessageQueue( new MessageQueue(topicRoute.getTopicName(), qd.getBrokerName(), i), brokerAddr); queueSet.add(mq); @@ -129,9 +129,9 @@ public class MessageQueueSelector { return queueSet.stream().sorted().collect(Collectors.toList()); } - private void buildBrokerActingQueues(String topic, List normalQueues) { - for (SelectableMessageQueue mq : normalQueues) { - SelectableMessageQueue brokerActingQueue = new SelectableMessageQueue( + private void buildBrokerActingQueues(String topic, List normalQueues) { + for (AddressableMessageQueue mq : normalQueues) { + AddressableMessageQueue brokerActingQueue = new AddressableMessageQueue( new MessageQueue(topic, mq.getMessageQueue().getBrokerName(), BROKER_ACTING_QUEUE_ID), mq.getBrokerAddr()); @@ -144,16 +144,16 @@ public class MessageQueueSelector { Collections.sort(brokerActingQueues); } - public final SelectableMessageQueue getQueueByBrokerName(String brokerName) { + public final AddressableMessageQueue getQueueByBrokerName(String brokerName) { return this.brokerNameQueueMap.get(brokerName); } - public final SelectableMessageQueue selectOne(boolean onlyBroker) { + public final AddressableMessageQueue selectOne(boolean onlyBroker) { int nextIndex = onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(); return selectOneByIndex(nextIndex, onlyBroker); } - public final SelectableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { + public final AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { if (onlyBroker) { if (brokerActingQueues.isEmpty()) { return null; @@ -167,11 +167,11 @@ public class MessageQueueSelector { return queues.get(Math.abs(index) % queues.size()); } - public List getQueues() { + public List getQueues() { return queues; } - public List getBrokerActingQueues() { + public List getBrokerActingQueues() { return brokerActingQueues; } 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 ef40bc5297..d8909a3f10 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 @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.exception.MQClientException; 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.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; @@ -87,6 +88,8 @@ public abstract class TopicRouteService extends AbstractStartAndShutdown { public abstract String getBrokerAddr(String brokerName) throws Exception; + public abstract AddressableMessageQueue buildAddressableMessageQueue(MessageQueue messageQueue) throws Exception; + protected static MessageQueueView getCacheMessageQueueWrapper(LoadingCache topicCache, String key) throws Exception { MessageQueueView res = topicCache.get(key); 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 ae8ac2b684..f243a75ce3 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 @@ -41,7 +41,7 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -172,9 +172,9 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { MessageQueueView messageQueueView = new MessageQueueView(TOPIC, topicRouteData); ReceiveMessageActivity.ReceiveMessageQueueSelector selector = new ReceiveMessageActivity.ReceiveMessageQueueSelector(""); - SelectableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); - SelectableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); - SelectableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); assertEquals(firstSelect, thirdSelect); assertNotEquals(firstSelect, secondSelect); 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 8ee4433763..07c6699ac2 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 @@ -45,7 +45,7 @@ import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.assertj.core.util.Lists; import org.junit.Before; @@ -327,9 +327,9 @@ public class SendMessageActivityTest extends BaseActivityTest { .build() ); - SelectableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); - SelectableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); - SelectableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue firstSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue secondSelect = selector.select(ProxyContext.create(), messageQueueView); + AddressableMessageQueue thirdSelect = selector.select(ProxyContext.create(), messageQueueView); assertEquals(firstSelect, thirdSelect); assertNotEquals(firstSelect, secondSelect); 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 99ebba4223..6a94a02b92 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 @@ -39,7 +39,7 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHead import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; import org.junit.Test; @@ -72,7 +72,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { public void testPopMessage() throws Throwable { final String tag = "tag"; final long invisibleTime = Duration.ofSeconds(15).toMillis(); - ArgumentCaptor messageQueueArgumentCaptor = ArgumentCaptor.forClass(SelectableMessageQueue.class); + ArgumentCaptor messageQueueArgumentCaptor = ArgumentCaptor.forClass(AddressableMessageQueue.class); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(PopMessageRequestHeader.class); List messageExtList = new ArrayList<>(); @@ -94,7 +94,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { when(this.messagingProcessor.forwardMessageToDeadLetterQueue(any(), any(), toDLQMessageIdArgumentCaptor.capture(), anyString(), anyString(), anyLong())) .thenReturn(CompletableFuture.completedFuture(mock(RemotingCommand.class))); - SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + AddressableMessageQueue messageQueue = mock(AddressableMessageQueue.class); PopResult popResult = this.consumerProcessor.popMessage( createContext(), (ctx, messageQueueView) -> messageQueue, diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 9f47dd8003..89b8c36ea9 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -35,7 +35,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; @@ -83,7 +83,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { List messageList = new ArrayList<>(); Message messageExt = createMessageExt(TOPIC, "tag", 0, 0); messageList.add(messageExt); - SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + AddressableMessageQueue messageQueue = mock(AddressableMessageQueue.class); when(messageQueue.getBrokerName()).thenReturn("mockBroker"); List sendResultList = this.producerProcessor.sendMessage( @@ -124,7 +124,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_RECONSUME_TIME, "1"); MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_MAX_RECONSUME_TIMES, "16"); messageExtList.add(messageExt); - SelectableMessageQueue messageQueue = mock(SelectableMessageQueue.class); + AddressableMessageQueue messageQueue = mock(AddressableMessageQueue.class); when(messageQueue.getBrokerName()).thenReturn("mockBroker"); List sendResultList = this.producerProcessor.sendMessage( diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java index 3058951a2c..e1524e5e8b 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java @@ -66,7 +66,7 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.service.channel.ChannelManager; import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; -import org.apache.rocketmq.proxy.service.route.SelectableMessageQueue; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; @@ -318,7 +318,7 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { return null; }); MessageQueue messageQueue = new MessageQueue(topic, brokerName, queueId); - CompletableFuture future = localMessageService.popMessage(proxyContext, new SelectableMessageQueue(messageQueue, ""), requestHeader, 1000L); + CompletableFuture future = localMessageService.popMessage(proxyContext, new AddressableMessageQueue(messageQueue, ""), requestHeader, 1000L); PopResult popResult = future.get(); assertThat(popResult.getPopTime()).isEqualTo(popTime); assertThat(popResult.getInvisibleTime()).isEqualTo(invisibleTime); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java index a59c4cf20a..e44ed28f4a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/route/MessageQueueSelectorTest.java @@ -39,16 +39,16 @@ public class MessageQueueSelectorTest extends BaseServiceTest { assertEquals(3, messageQueueSelector.getQueues().size()); assertEquals(1, messageQueueSelector.getBrokerActingQueues().size()); for (int i = 0; i < messageQueueSelector.getQueues().size(); i++) { - SelectableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); + AddressableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); assertEquals(i, messageQueue.getQueueId()); } - SelectableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); + AddressableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); assertEquals(brokerQueue, messageQueueSelector.getBrokerActingQueues().get(0)); assertEquals(brokerQueue, messageQueueSelector.selectOne(true)); assertEquals(brokerQueue, messageQueueSelector.selectOneByIndex(3, true)); - SelectableMessageQueue queue = messageQueueSelector.selectOne(false); + AddressableMessageQueue queue = messageQueueSelector.selectOne(false); messageQueueSelector.selectOne(false); messageQueueSelector.selectOne(false); assertEquals(queue, messageQueueSelector.selectOne(false)); @@ -67,16 +67,16 @@ public class MessageQueueSelectorTest extends BaseServiceTest { assertEquals(3, messageQueueSelector.getQueues().size()); assertEquals(1, messageQueueSelector.getBrokerActingQueues().size()); for (int i = 0; i < messageQueueSelector.getQueues().size(); i++) { - SelectableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); + AddressableMessageQueue messageQueue = messageQueueSelector.getQueues().get(i); assertEquals(i, messageQueue.getQueueId()); } - SelectableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); + AddressableMessageQueue brokerQueue = messageQueueSelector.getQueueByBrokerName(BROKER_NAME); assertEquals(brokerQueue, messageQueueSelector.getBrokerActingQueues().get(0)); assertEquals(brokerQueue, messageQueueSelector.selectOne(true)); assertEquals(brokerQueue, messageQueueSelector.selectOneByIndex(3, true)); - SelectableMessageQueue queue = messageQueueSelector.selectOne(false); + AddressableMessageQueue queue = messageQueueSelector.selectOne(false); messageQueueSelector.selectOne(false); messageQueueSelector.selectOne(false); assertEquals(queue, messageQueueSelector.selectOne(false)); From 55bf26f2db133f28b4f8baea889a92c980af8226 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 15 Jun 2022 19:26:53 +0800 Subject: [PATCH 251/338] [ISSUE #4384] Remove TimeUnit in nextDelayDuration --- .../rocketmq/proxy/processor/ReceiptHandleProcessor.java | 2 +- .../rocketmq/proxy/processor/ReceiptHandleProcessorTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 533b2b375e..cc92eb9a61 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -144,7 +144,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } else { CompletableFuture future = messagingProcessor.changeInvisibleTime(ProxyContext.create(), handle, messageReceiptHandle.getMessageId(), messageReceiptHandle.getGroup(), - messageReceiptHandle.getTopic(), retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes(), TimeUnit.MILLISECONDS)); + messageReceiptHandle.getTopic(), retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes())); future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { removeReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle()); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index c8587a8294..dc47916b73 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.proxy.processor; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; @@ -136,7 +135,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes, TimeUnit.MILLISECONDS))); + Mockito.eq(group), Mockito.eq(topic), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes))); } From 3cabbb0502b11862677ed835615143a092d4fc36 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 15 Jun 2022 21:04:14 +0800 Subject: [PATCH 252/338] [ISSUE #3949] Add offset related rpc --- .../proxy/processor/ConsumerProcessor.java | 53 +++++++++++++- .../processor/DefaultMessagingProcessor.java | 16 +++++ .../proxy/processor/MessagingProcessor.java | 19 +++++ .../message/ClusterMessageService.java | 33 +++++++++ .../service/message/LocalMessageService.java | 21 ++++++ .../proxy/service/message/MessageService.java | 24 +++++++ .../service/mqclient/MQClientAPIExt.java | 72 +++++++++++++++++++ 7 files changed, 236 insertions(+), 2 deletions(-) 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 596dbc1b34..b3862fc0b2 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 @@ -38,8 +38,11 @@ import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; import org.apache.rocketmq.common.protocol.body.UnlockBatchRequestBody; import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; @@ -257,6 +260,23 @@ public class ConsumerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } + public CompletableFuture queryConsumerOffset(ProxyContext ctx, MessageQueue messageQueue, + String consumerGroup, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + AddressableMessageQueue addressableMessageQueue = serviceManager.getTopicRouteService() + .buildAddressableMessageQueue(messageQueue); + QueryConsumerOffsetRequestHeader requestHeader = new QueryConsumerOffsetRequestHeader(); + requestHeader.setConsumerGroup(consumerGroup); + requestHeader.setTopic(addressableMessageQueue.getTopic()); + requestHeader.setQueueId(addressableMessageQueue.getQueueId()); + future = serviceManager.getMessageService().queryConsumerOffset(ctx, addressableMessageQueue, requestHeader, timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return FutureUtils.addExecutor(future, this.executor); + } + public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, String clientId, long timeoutMillis) { CompletableFuture> future = new CompletableFuture<>(); @@ -288,8 +308,7 @@ public class ConsumerProcessor extends AbstractProcessor { } public CompletableFuture unlockBatchMQ(ProxyContext ctx, Set mqSet, - String consumerGroup, - String clientId, long timeoutMillis) { + String consumerGroup, String clientId, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); Set addressableMessageQueueSet = buildAddressableSet(mqSet); Map> messageQueueSetMap = buildAddressableMapByBrokerName(addressableMessageQueueSet); @@ -317,6 +336,36 @@ public class ConsumerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } + public CompletableFuture getMaxOffset(ProxyContext ctx, MessageQueue messageQueue, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + AddressableMessageQueue addressableMessageQueue = serviceManager.getTopicRouteService() + .buildAddressableMessageQueue(messageQueue); + GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); + requestHeader.setTopic(addressableMessageQueue.getTopic()); + requestHeader.setQueueId(addressableMessageQueue.getQueueId()); + future = serviceManager.getMessageService().getMaxOffset(ctx, addressableMessageQueue, requestHeader, timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return FutureUtils.addExecutor(future, this.executor); + } + + public CompletableFuture getMinOffset(ProxyContext ctx, MessageQueue messageQueue, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + AddressableMessageQueue addressableMessageQueue = serviceManager.getTopicRouteService() + .buildAddressableMessageQueue(messageQueue); + GetMinOffsetRequestHeader requestHeader = new GetMinOffsetRequestHeader(); + requestHeader.setTopic(addressableMessageQueue.getTopic()); + requestHeader.setQueueId(addressableMessageQueue.getQueueId()); + future = serviceManager.getMessageService().getMinOffset(ctx, addressableMessageQueue, requestHeader, timeoutMillis); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return FutureUtils.addExecutor(future, this.executor); + } + protected Set buildAddressableSet(Set mqSet) { return mqSet.stream().map(mq -> { try { 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 813a6b7527..59fa8afb60 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 @@ -192,6 +192,12 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen return this.consumerProcessor.updateConsumerOffset(ctx, messageQueue, consumerGroup, commitOffset, timeoutMillis); } + @Override + public CompletableFuture queryConsumerOffset(ProxyContext ctx, MessageQueue messageQueue, + String consumerGroup, long timeoutMillis) { + return this.consumerProcessor.queryConsumerOffset(ctx, messageQueue, consumerGroup, timeoutMillis); + } + @Override public CompletableFuture> lockBatchMQ(ProxyContext ctx, Set mqSet, String consumerGroup, String clientId, long timeoutMillis) { @@ -205,6 +211,16 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen return this.consumerProcessor.unlockBatchMQ(ctx, mqSet, consumerGroup, clientId, timeoutMillis); } + @Override + public CompletableFuture getMaxOffset(ProxyContext ctx, MessageQueue messageQueue, long timeoutMillis) { + return this.consumerProcessor.getMaxOffset(ctx, messageQueue, timeoutMillis); + } + + @Override + public CompletableFuture getMinOffset(ProxyContext ctx, MessageQueue messageQueue, long timeoutMillis) { + return this.consumerProcessor.getMinOffset(ctx, messageQueue, timeoutMillis); + } + @Override public void registerProducer(ProxyContext ctx, String producerGroup, ClientChannelInfo clientChannelInfo) { this.clientProcessor.registerProducer(ctx, producerGroup, clientChannelInfo); 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 5ecdb65727..70d994c2dc 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 @@ -198,6 +198,13 @@ public interface MessagingProcessor extends StartAndShutdown { long timeoutMillis ); + CompletableFuture queryConsumerOffset( + ProxyContext ctx, + MessageQueue messageQueue, + String consumerGroup, + long timeoutMillis + ); + CompletableFuture> lockBatchMQ( ProxyContext ctx, Set mqSet, @@ -214,6 +221,18 @@ public interface MessagingProcessor extends StartAndShutdown { long timeoutMillis ); + CompletableFuture getMaxOffset( + ProxyContext ctx, + MessageQueue messageQueue, + long timeoutMillis + ); + + CompletableFuture getMinOffset( + ProxyContext ctx, + MessageQueue messageQueue, + long timeoutMillis + ); + void registerProducer( ProxyContext ctx, String producerGroup, 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 e4b92d8591..cc32143c08 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 @@ -34,8 +34,11 @@ import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -139,6 +142,16 @@ public class ClusterMessageService implements MessageService { ); } + @Override + public CompletableFuture queryConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + QueryConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().queryConsumerOffsetWithFuture( + messageQueue.getBrokerAddr(), + requestHeader, + timeoutMillis + ); + } + @Override public CompletableFuture updateConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { @@ -169,6 +182,26 @@ public class ClusterMessageService implements MessageService { ); } + @Override + public CompletableFuture getMaxOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + GetMaxOffsetRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().getMaxOffset( + messageQueue.getBrokerAddr(), + requestHeader, + timeoutMillis + ); + } + + @Override + public CompletableFuture getMinOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + GetMinOffsetRequestHeader requestHeader, long timeoutMillis) { + return this.mqClientAPIFactory.getClient().getMinOffset( + messageQueue.getBrokerAddr(), + requestHeader, + timeoutMillis + ); + } + protected String resolveBrokerAddr(ReceiptHandle handle) { return resolveBrokerAddr(handle.getBrokerName()); } 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 3bf121b8dc..8de11b87e8 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 @@ -53,9 +53,12 @@ import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeResponseHea import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; @@ -357,6 +360,12 @@ public class LocalMessageService implements MessageService { throw new NotImplementedException("pullMessage is not implemented in LocalMessageService"); } + @Override + public CompletableFuture queryConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + QueryConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { + throw new NotImplementedException("queryConsumerOffset is not implemented in LocalMessageService"); + } + @Override public CompletableFuture updateConsumerOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, UpdateConsumerOffsetRequestHeader requestHeader, long timeoutMillis) { @@ -374,4 +383,16 @@ public class LocalMessageService implements MessageService { UnlockBatchRequestBody requestBody, long timeoutMillis) { throw new NotImplementedException("unlockBatchMQ is not implemented in LocalMessageService"); } + + @Override + public CompletableFuture getMaxOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + GetMaxOffsetRequestHeader requestHeader, long timeoutMillis) { + throw new NotImplementedException("getMaxOffset is not implemented in LocalMessageService"); + } + + @Override + public CompletableFuture getMinOffset(ProxyContext ctx, AddressableMessageQueue messageQueue, + GetMinOffsetRequestHeader requestHeader, long timeoutMillis) { + throw new NotImplementedException("getMinOffset is not implemented in LocalMessageService"); + } } 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 bdef99c2c3..45ffce4933 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 @@ -33,8 +33,11 @@ import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -98,6 +101,13 @@ public interface MessageService { long timeoutMillis ); + CompletableFuture queryConsumerOffset( + ProxyContext ctx, + AddressableMessageQueue messageQueue, + QueryConsumerOffsetRequestHeader requestHeader, + long timeoutMillis + ); + CompletableFuture updateConsumerOffset( ProxyContext ctx, AddressableMessageQueue messageQueue, @@ -118,4 +128,18 @@ public interface MessageService { UnlockBatchRequestBody requestBody, long timeoutMillis ); + + CompletableFuture getMaxOffset( + ProxyContext ctx, + AddressableMessageQueue messageQueue, + GetMaxOffsetRequestHeader requestHeader, + long timeoutMillis + ); + + CompletableFuture getMinOffset( + ProxyContext ctx, + AddressableMessageQueue messageQueue, + GetMinOffsetRequestHeader requestHeader, + long timeoutMillis + ); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 5380f540ba..683146f0eb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -31,6 +31,7 @@ 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; import org.apache.rocketmq.client.impl.MQClientAPIImpl; @@ -55,8 +56,12 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestH import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody; import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.GetMaxOffsetResponseHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.GetMinOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader; +import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SearchOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; @@ -65,6 +70,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.ResponseFuture; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -356,6 +362,45 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } + public CompletableFuture queryConsumerOffsetWithFuture( + String brokerAddr, + 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 = + 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; + } + } else { + future.completeExceptionally(processNullResponseErr(responseFuture)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + public CompletableFuture updateConsumerOffsetOneWay( String brokerAddr, UpdateConsumerOffsetRequestHeader header, @@ -442,6 +487,33 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } + public CompletableFuture getMinOffset(String brokerAddr, GetMinOffsetRequestHeader requestHeader, long timeoutMillis) { + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MIN_OFFSET, requestHeader); + + CompletableFuture future = new CompletableFuture<>(); + try { + this.getRemotingClient().invokeAsync(brokerAddr, request, timeoutMillis, responseFuture -> { + RemotingCommand response = responseFuture.getResponseCommand(); + if (response != null) { + if (ResponseCode.SUCCESS == response.getCode()) { + try { + GetMinOffsetResponseHeader responseHeader = response.decodeCommandCustomHeader(GetMinOffsetResponseHeader.class); + future.complete(responseHeader.getOffset()); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } + future.completeExceptionally(new MQBrokerException(response.getCode(), response.getRemark())); + } else { + future.completeExceptionally(processNullResponseErr(responseFuture)); + } + }); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; + } + public CompletableFuture searchOffset(String brokerAddr, SearchOffsetRequestHeader requestHeader, long timeoutMillis) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); From b33915a4eec737dea93a3026a5442b88cce39bdb Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 16 Jun 2022 16:51:33 +0800 Subject: [PATCH 253/338] [ISSUE #3949] add selectNextOne in MessageQueueSelector --- .../service/route/MessageQueueSelector.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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 04427d3de9..cf5314c79f 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 @@ -144,16 +144,30 @@ public class MessageQueueSelector { Collections.sort(brokerActingQueues); } - public final AddressableMessageQueue getQueueByBrokerName(String brokerName) { + public AddressableMessageQueue getQueueByBrokerName(String brokerName) { return this.brokerNameQueueMap.get(brokerName); } - public final AddressableMessageQueue selectOne(boolean onlyBroker) { + public AddressableMessageQueue selectOne(boolean onlyBroker) { int nextIndex = onlyBroker ? brokerIndex.getAndIncrement() : queueIndex.getAndIncrement(); return selectOneByIndex(nextIndex, onlyBroker); } - public final AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { + public AddressableMessageQueue selectNextOne(AddressableMessageQueue last) { + boolean onlyBroker = last.getQueueId() < 0; + AddressableMessageQueue newOne = last; + int count = onlyBroker ? brokerActingQueues.size() : queues.size(); + + for (int i = 0; i < count; i++) { + newOne = selectOne(onlyBroker); + if (!newOne.getBrokerName().equals(last.getBrokerName()) || newOne.getQueueId() != last.getQueueId()) { + break; + } + } + return newOne; + } + + public AddressableMessageQueue selectOneByIndex(int index, boolean onlyBroker) { if (onlyBroker) { if (brokerActingQueues.isEmpty()) { return null; From a465e2b729744f614fc1a4cae36c67c33d0c38b4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 17 Jun 2022 15:43:29 +0800 Subject: [PATCH 254/338] [ISSUE #3949] use clientID instead of channelKey in ReceiptHandleProcessor --- .../proxy/common/ContextVariable.java | 1 - .../proxy/common/utils/ChannelUtils.java | 26 ------------------- .../grpc/v2/AbstractMessingActivity.java | 11 ++------ .../grpc/v2/consumer/AckMessageActivity.java | 9 +++---- .../ChangeInvisibleDurationActivity.java | 9 +++---- .../v2/consumer/ReceiveMessageActivity.java | 6 ++--- .../processor/ReceiptHandleProcessor.java | 26 ++++++++++++------- .../processor/ReceiptHandleProcessorTest.java | 14 +++++----- .../ClusterTransactionServiceTest.java | 5 ++-- 9 files changed, 38 insertions(+), 69 deletions(-) delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index df102b9648..27cc04cc2a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -22,5 +22,4 @@ public class ContextVariable { public final static String LOCAL_ADDRESS = "local-address"; public static final String CLIENT_ID = "client-id"; public static final String LANGUAGE = "language"; - public final static String CHANNEL_KEY = "channel-key"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java deleted file mode 100644 index 632506ee77..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ChannelUtils.java +++ /dev/null @@ -1,26 +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.proxy.common.utils; - -import io.netty.channel.Channel; - -public class ChannelUtils { - public static String buildChannelKey(Channel channel, String groupName) { - return channel.id().asLongText() + "%" + groupName; - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 6e94e68723..b07f8a0979 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -17,10 +17,8 @@ package org.apache.rocketmq.proxy.grpc.v2; import io.grpc.Context; -import io.netty.channel.Channel; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.common.utils.ChannelUtils; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; @@ -41,16 +39,11 @@ public abstract class AbstractMessingActivity { } protected ProxyContext createContext(Context ctx) { + String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); return ProxyContext.create() .withVal(ContextVariable.LOCAL_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)) .withVal(ContextVariable.REMOTE_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS)) - .withVal(ContextVariable.CLIENT_ID, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) + .withVal(ContextVariable.CLIENT_ID, clientId) .withVal(ContextVariable.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); } - - protected void attachChannelId(Context ctx, ProxyContext context, String groupName) { - String clientId = context.getVal(ContextVariable.CLIENT_ID); - Channel channel = grpcChannelManager.createChannel(ctx, groupName, clientId); - context.withVal(ContextVariable.CHANNEL_KEY, ChannelUtils.buildChannelKey(channel, groupName)); - } } 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 e76dc42780..9f155ec43b 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 @@ -51,8 +51,6 @@ public class AckMessageActivity extends AbstractMessingActivity { public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { ProxyContext proxyContext = createContext(ctx); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - attachChannelId(ctx, proxyContext, groupName); CompletableFuture future = new CompletableFuture<>(); try { @@ -102,16 +100,17 @@ public class AckMessageActivity extends AbstractMessingActivity { try { ReceiptHandle receiptHandle = ReceiptHandle.decode(ackMessageEntry.getReceiptHandle()); + String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); CompletableFuture ackResultFuture = this.messagingProcessor.ackMessage( ctx, receiptHandle, ackMessageEntry.getMessageId(), - GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + group, GrpcConverter.wrapResourceWithNamespace(request.getTopic())); ackResultFuture.thenAccept(result -> { if (AckStatus.OK.equals(result.getStatus())) { - String channelId = ctx.getVal(ContextVariable.CHANNEL_KEY); - receiptHandleProcessor.removeReceiptHandle(channelId, ackMessageEntry.getReceiptHandle()); + String clientID = ctx.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.removeReceiptHandle(clientID, group, ackMessageEntry.getReceiptHandle()); } future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); }).exceptionally(throwable -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index f6f2bbec18..287b1152cd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -47,24 +47,23 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { public CompletableFuture changeInvisibleDuration(Context ctx, ChangeInvisibleDurationRequest request) { ProxyContext context = createContext(ctx); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - attachChannelId(ctx, context, groupName); CompletableFuture future = new CompletableFuture<>(); try { ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); + String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); return this.messagingProcessor.changeInvisibleTime( context, receiptHandle, request.getMessageId(), - GrpcConverter.wrapResourceWithNamespace(request.getGroup()), + group, GrpcConverter.wrapResourceWithNamespace(request.getTopic()), Durations.toMillis(request.getInvisibleDuration()) ).thenApply(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); - receiptHandleProcessor.removeReceiptHandle(channelId, receiptHandle.getReceiptHandle()); + String clientID = context.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.removeReceiptHandle(clientID, group, receiptHandle.getReceiptHandle()); } return convertToChangeInvisibleDurationResponse(context, request, ackResult); }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 1b8087b20c..0aedcb54e9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -62,8 +62,6 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { StreamObserver responseObserver) { ProxyContext proxyContext = createContext(ctx); ReceiveMessageResponseStreamWriter writer = createWriter(proxyContext, responseObserver); - String groupName = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); - attachChannelId(ctx, proxyContext, groupName); try { Settings settings = this.grpcClientSettingsManager.getClientSettings(proxyContext); @@ -123,8 +121,8 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { MessageReceiptHandle messageReceiptHandle = new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); - String channelId = proxyContext.getVal(ContextVariable.CHANNEL_KEY); - receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + String clientID = proxyContext.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(clientID, group, receiptHandle, messageReceiptHandle); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index cc92eb9a61..c665fe559f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.processor; -import io.netty.channel.Channel; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -42,7 +41,6 @@ import org.apache.rocketmq.proxy.common.MessageReceiptHandle; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.ReceiptHandleGroup; import org.apache.rocketmq.proxy.common.StartAndShutdown; -import org.apache.rocketmq.proxy.common.utils.ChannelUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.slf4j.Logger; @@ -70,8 +68,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } if (args[0] instanceof ClientChannelInfo) { ClientChannelInfo clientChannelInfo = (ClientChannelInfo) args[0]; - Channel channel = clientChannelInfo.getChannel(); - clearGroup(ChannelUtils.buildChannelKey(channel, group)); + clearGroup(buildKey(clientChannelInfo.getClientId(), group)); } } } @@ -153,7 +150,16 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } } - public void addReceiptHandle(String key, String receiptHandle, + protected String buildKey(String clientID, String group) { + return clientID + "%" + group; + } + + public void addReceiptHandle(String clientID, String group, String receiptHandle, + MessageReceiptHandle messageReceiptHandle) { + this.addReceiptHandle(buildKey(clientID, group), receiptHandle, messageReceiptHandle); + } + + protected void addReceiptHandle(String key, String receiptHandle, MessageReceiptHandle messageReceiptHandle) { if (key == null) { return; @@ -162,7 +168,11 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { k -> new ReceiptHandleGroup()).put(receiptHandle, messageReceiptHandle); } - public void removeReceiptHandle(String key, String receiptHandle) { + public void removeReceiptHandle(String clientID, String group, String receiptHandle) { + this.removeReceiptHandle(buildKey(clientID, group), receiptHandle); + } + + protected void removeReceiptHandle(String key, String receiptHandle) { if (key == null) { return; } @@ -194,8 +204,4 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } ); } - - protected String keyWithChannelId(String channelId, String groupName) { - return channelId + "%" + groupName; - } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index dc47916b73..c12bbc9c52 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -59,7 +59,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Before public void setup() { - context.withVal(ContextVariable.CHANNEL_KEY, "channel-id"); + context.withVal(ContextVariable.CLIENT_ID, "channel-id"); receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); Mockito.doNothing().when(messagingProcessor).registerConsumerListener(Mockito.any(ConsumerIdsChangeListener.class)); messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, @@ -68,7 +68,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testAddReceiptHandle() { - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(new SubscriptionGroupConfig()); receiptHandleProcessor.scheduleRenewTask(); @@ -79,7 +79,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testRenewReceiptHandle() { - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); @@ -128,7 +128,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .build().encode(); messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, reconsumeTimes, newInvisibleTime); - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); @@ -154,7 +154,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .build().encode(); messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, newReceiptHandle, messageId, offset, reconsumeTimes, invisibleTime); - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); @@ -166,7 +166,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testRemoveReceiptHandle() { - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); receiptHandleProcessor.removeReceiptHandle(channelId, receiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); @@ -179,7 +179,7 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testClearGroup() { - String channelId = context.getVal(ContextVariable.CHANNEL_KEY); + String channelId = context.getVal(ContextVariable.CLIENT_ID); receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); receiptHandleProcessor.clearGroup(channelId); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java index c9b3b17657..bb147a6b0d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java @@ -21,6 +21,7 @@ import java.time.Duration; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.common.protocol.heartbeat.ProducerData; @@ -111,11 +112,11 @@ public class ClusterTransactionServiceTest extends BaseServiceTest { ArgumentCaptor brokerAddrArgumentCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor heartbeatDataArgumentCaptor = ArgumentCaptor.forClass(HeartbeatData.class); - doNothing().when(mqClientAPIExt).sendHeartbeatOneway( + when(mqClientAPIExt.sendHeartbeatOneway( brokerAddrArgumentCaptor.capture(), heartbeatDataArgumentCaptor.capture(), anyLong() - ); + )).thenReturn(CompletableFuture.completedFuture(null)); this.clusterTransactionService.scanProducerHeartBeat(); From 830e4fced41ecb40ea084dcead6d4117fcf0ea5a Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 16 Jun 2022 20:52:30 +0800 Subject: [PATCH 255/338] [ISSUE #3949] Add CLIENT_REGISTER --- .../rocketmq/broker/client/ConsumerGroupEvent.java | 4 ++++ .../apache/rocketmq/broker/client/ConsumerManager.java | 9 ++++++--- .../broker/client/DefaultConsumerIdsChangeListener.java | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java index 2318edb5f3..6c0a58db06 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java @@ -30,6 +30,10 @@ public enum ConsumerGroupEvent { * The group of consumer is registered. */ REGISTER, + /** + * The client of this consumer is new registered. + */ + CLIENT_REGISTER, /** * The client of this consumer is unregistered. */ diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java index 2f0f9a6789..ed277a711d 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java @@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentMap; import io.netty.channel.Channel; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; @@ -98,7 +99,7 @@ public class ConsumerManager { ConsumerGroupInfo info = next.getValue(); ClientChannelInfo clientChannelInfo = info.doChannelCloseEvent(remoteAddr, channel); if (clientChannelInfo != null) { - callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, next.getKey(), clientChannelInfo); + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, next.getKey(), clientChannelInfo, info.getSubscribeTopics()); if (info.getChannelInfoTable().isEmpty()) { ConsumerGroupInfo remove = this.consumerTable.remove(next.getKey()); if (remove != null) { @@ -120,6 +121,8 @@ public class ConsumerManager { long start = System.currentTimeMillis(); ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group); if (null == consumerGroupInfo) { + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_REGISTER, group, clientChannelInfo, + subList.stream().map(SubscriptionData::getTopic).collect(Collectors.toSet())); ConsumerGroupInfo tmp = new ConsumerGroupInfo(group, consumeType, messageModel, consumeFromWhere); ConsumerGroupInfo prev = this.consumerTable.putIfAbsent(group, tmp); consumerGroupInfo = prev != null ? prev : tmp; @@ -150,7 +153,7 @@ public class ConsumerManager { if (null != consumerGroupInfo) { boolean removed = consumerGroupInfo.unregisterChannel(clientChannelInfo); if (removed) { - callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo, consumerGroupInfo.getSubscribeTopics()); } if (consumerGroupInfo.getChannelInfoTable().isEmpty()) { ConsumerGroupInfo remove = this.consumerTable.remove(group); @@ -184,7 +187,7 @@ public class ConsumerManager { LOGGER.warn( "SCAN: remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}", RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group); - callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo); + callConsumerIdsChangeListener(ConsumerGroupEvent.CLIENT_UNREGISTER, group, clientChannelInfo, consumerGroupInfo.getSubscribeTopics()); RemotingUtil.closeChannel(clientChannelInfo.getChannel()); itChannel.remove(); } 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 72ccc8f16f..1d040245fc 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 @@ -90,6 +90,7 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen Collection subscriptionDataList = (Collection) args[0]; this.brokerController.getConsumerFilterManager().register(group, subscriptionDataList); break; + case CLIENT_REGISTER: case CLIENT_UNREGISTER: break; default: From 618459d210282a95f021c8053d3644d74ca90d28 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Fri, 17 Jun 2022 18:23:50 +0800 Subject: [PATCH 256/338] [ISSUE #3949] use proxyContext directly in activity --- .../proxy/common/ContextVariable.java | 5 +- .../rocketmq/proxy/common/ProxyContext.java | 46 ++++ .../grpc/v2/AbstractMessingActivity.java | 14 -- .../grpc/v2/DefaultGrpcMessingActivity.java | 26 ++- .../grpc/v2/GrpcMessagingApplication.java | 219 ++++++++---------- .../proxy/grpc/v2/GrpcMessingActivity.java | 24 +- .../grpc/v2/channel/GrpcChannelManager.java | 4 +- .../grpc/v2/channel/GrpcClientChannel.java | 10 +- .../proxy/grpc/v2/client/ClientActivity.java | 44 ++-- .../v2/common/GrpcClientSettingsManager.java | 5 +- .../grpc/v2/consumer/AckMessageActivity.java | 11 +- .../ChangeInvisibleDurationActivity.java | 15 +- .../v2/consumer/ReceiveMessageActivity.java | 33 ++- .../producer/ForwardMessageToDLQActivity.java | 8 +- .../grpc/v2/producer/SendMessageActivity.java | 15 +- .../proxy/grpc/v2/route/RouteActivity.java | 12 +- .../transaction/EndTransactionActivity.java | 6 +- .../proxy/processor/QueueSelector.java | 2 +- .../proxy/service/channel/ChannelManager.java | 15 +- .../service/mqclient/MQClientAPIExt.java | 6 +- .../service/relay/LocalProxyRelayService.java | 5 +- .../proxy/service/relay/ProxyChannel.java | 11 +- .../proxy/grpc/v2/BaseActivityTest.java | 20 +- .../grpc/v2/GrpcMessagingApplicationTest.java | 19 +- .../grpc/v2/client/ClientActivityTest.java | 24 +- .../consumer/ReceiveMessageActivityTest.java | 2 +- .../v2/producer/SendMessageActivityTest.java | 2 +- .../processor/ConsumerProcessorTest.java | 2 +- .../processor/ReceiptHandleProcessorTest.java | 5 +- .../ClusterTransactionServiceTest.java | 1 - 30 files changed, 314 insertions(+), 297 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index 27cc04cc2a..b2581180b4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -18,8 +18,9 @@ package org.apache.rocketmq.proxy.common; public class ContextVariable { - public final static String REMOTE_ADDRESS = "remote-address"; - public final static String LOCAL_ADDRESS = "local-address"; + public static final String REMOTE_ADDRESS = "remote-address"; + public static final String LOCAL_ADDRESS = "local-address"; public static final String CLIENT_ID = "client-id"; public static final String LANGUAGE = "language"; + public static final String REMAINING_MS = "remaining-ms"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java index be0f6d4b00..0c13e45699 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java @@ -39,4 +39,50 @@ public class ProxyContext { public T getVal(String key) { return (T) this.value.get(key); } + + public ProxyContext setLocalAddress(String localAddress) { + this.withVal(ContextVariable.LOCAL_ADDRESS, localAddress); + return this; + } + + public String getLocalAddress() { + return this.getVal(ContextVariable.LOCAL_ADDRESS); + } + + public ProxyContext setRemoteAddress(String remoteAddress) { + this.withVal(ContextVariable.REMOTE_ADDRESS, remoteAddress); + return this; + } + + public String getRemoteAddress() { + return this.getVal(ContextVariable.REMOTE_ADDRESS); + } + + public ProxyContext setClientID(String clientID) { + this.withVal(ContextVariable.CLIENT_ID, clientID); + return this; + } + + public String getClientID() { + return this.getVal(ContextVariable.CLIENT_ID); + } + + public ProxyContext setLanguage(String language) { + this.withVal(ContextVariable.LANGUAGE, language); + return this; + } + + public String getLanguage() { + return this.getVal(ContextVariable.LANGUAGE); + } + + public ProxyContext setRemainingMs(Long remainingMs) { + this.withVal(ContextVariable.REMAINING_MS, remainingMs); + return this; + } + + public Long getRemainingMs() { + return this.getVal(ContextVariable.REMAINING_MS); + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index b07f8a0979..2ea08b462d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -16,14 +16,9 @@ */ package org.apache.rocketmq.proxy.grpc.v2; -import io.grpc.Context; -import org.apache.rocketmq.proxy.common.ContextVariable; -import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; import org.apache.rocketmq.proxy.processor.MessagingProcessor; -import org.apache.rocketmq.remoting.protocol.LanguageCode; public abstract class AbstractMessingActivity { @@ -37,13 +32,4 @@ public abstract class AbstractMessingActivity { this.grpcClientSettingsManager = grpcClientSettingsManager; this.grpcChannelManager = grpcChannelManager; } - - protected ProxyContext createContext(Context ctx) { - String clientId = InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID); - return ProxyContext.create() - .withVal(ContextVariable.LOCAL_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)) - .withVal(ContextVariable.REMOTE_ADDRESS, InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS)) - .withVal(ContextVariable.CLIENT_ID, clientId) - .withVal(ContextVariable.LANGUAGE, LanguageCode.valueOf(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE))); - } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 1052246189..c3215656fc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -37,13 +37,13 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.AbstractStartAndShutdown; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.client.ClientActivity; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcClientSettingsManager; @@ -85,61 +85,63 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme } @Override - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + public CompletableFuture queryRoute(ProxyContext ctx, QueryRouteRequest request) { return this.routeActivity.queryRoute(ctx, request); } @Override - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + public CompletableFuture heartbeat(ProxyContext ctx, HeartbeatRequest request) { return this.clientActivity.heartbeat(ctx, request); } @Override - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { + public CompletableFuture sendMessage(ProxyContext ctx, SendMessageRequest request) { return this.sendMessageActivity.sendMessage(ctx, request); } @Override - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + public CompletableFuture queryAssignment(ProxyContext ctx, + QueryAssignmentRequest request) { return this.routeActivity.queryAssignment(ctx, request); } @Override - public void receiveMessage(Context ctx, ReceiveMessageRequest request, + public void receiveMessage(ProxyContext ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { this.receiveMessageActivity.receiveMessage(ctx, request, responseObserver); } @Override - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { + public CompletableFuture ackMessage(ProxyContext ctx, AckMessageRequest request) { return this.ackMessageActivity.ackMessage(ctx, request); } @Override - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + public CompletableFuture forwardMessageToDeadLetterQueue(ProxyContext ctx, ForwardMessageToDeadLetterQueueRequest request) { return this.forwardMessageToDLQActivity.forwardMessageToDeadLetterQueue(ctx, request); } @Override - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + public CompletableFuture endTransaction(ProxyContext ctx, EndTransactionRequest request) { return this.endTransactionActivity.endTransaction(ctx, request); } @Override - public CompletableFuture notifyClientTermination(Context ctx, + public CompletableFuture notifyClientTermination(ProxyContext ctx, NotifyClientTerminationRequest request) { return this.clientActivity.notifyClientTermination(ctx, request); } @Override - public CompletableFuture changeInvisibleDuration(Context ctx, + public CompletableFuture changeInvisibleDuration(ProxyContext ctx, ChangeInvisibleDurationRequest request) { return this.changeInvisibleDurationActivity.changeInvisibleDuration(ctx, request); } @Override - public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + public StreamObserver telemetry(ProxyContext ctx, + StreamObserver responseObserver) { return this.clientActivity.telemetry(ctx, responseObserver); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 806504d683..e0c06dd587 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -43,16 +43,18 @@ import apache.rocketmq.v2.Status; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; @@ -142,64 +144,72 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ return ResponseBuilder.buildStatus(t); } - protected void addExecutor(ExecutorService executor, Runnable runnable, StreamObserver responseObserver, + protected void addExecutor(ExecutorService executor, ProxyContext context, V request, Runnable runnable, + StreamObserver responseObserver, T executeRejectResponse) { - executor.submit(new GrpcTask(runnable, responseObserver, executeRejectResponse)); + executor.submit(new GrpcTask(runnable, request, responseObserver, executeRejectResponse)); + } + + protected void writeResponse(ProxyContext context, V request, T response, StreamObserver responseObserver, + Throwable t, Function errorResponseCreator) { + if (t != null) { + ResponseWriter.write( + responseObserver, + errorResponseCreator.apply(convertExceptionToStatus(t)) + ); + } else { + ResponseWriter.write(responseObserver, response); + } + } + + protected ProxyContext createContext() { + Context ctx = Context.current(); + ProxyContext context = ProxyContext.create() + .setLocalAddress(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)) + .setRemoteAddress(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS)) + .setClientID(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) + .setLanguage(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE)); + if (ctx.getDeadline() != null) { + context.setRemainingMs(ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS)); + } + return context; } @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.routeThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.queryRoute(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryRouteResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.queryRoute(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> QueryRouteResponse.newBuilder().setStatus(status).build())), responseObserver, QueryRouteResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.clientManagerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.heartbeat(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - HeartbeatResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.heartbeat(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> HeartbeatResponse.newBuilder().setStatus(status).build())), responseObserver, HeartbeatResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.producerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.sendMessage(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - SendMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.sendMessage(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> SendMessageResponse.newBuilder().setStatus(status).build())), responseObserver, SendMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @@ -207,28 +217,24 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.routeThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.queryAssignment(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - QueryAssignmentResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.queryAssignment(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> QueryAssignmentResponse.newBuilder().setStatus(status).build())), responseObserver, QueryAssignmentResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.consumerThreadPoolExecutor, - () -> grpcMessingActivity.receiveMessage(ctx, request, responseObserver), + context, + request, + () -> grpcMessingActivity.receiveMessage(context, request, responseObserver), responseObserver, ReceiveMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); @@ -236,19 +242,13 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.consumerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.ackMessage(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - AckMessageResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.ackMessage(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> AckMessageResponse.newBuilder().setStatus(status).build())), responseObserver, AckMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); @@ -257,38 +257,26 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.producerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.forwardMessageToDeadLetterQueue(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.forwardMessageToDeadLetterQueue(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(status).build())), responseObserver, ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @Override public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.transactionThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.endTransaction(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - EndTransactionResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.endTransaction(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> EndTransactionResponse.newBuilder().setStatus(status).build())), responseObserver, EndTransactionResponse.newBuilder().setStatus(flowLimitStatus()).build()); } @@ -296,19 +284,13 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.clientManagerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.notifyClientTermination(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - NotifyClientTerminationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.notifyClientTermination(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> NotifyClientTerminationResponse.newBuilder().setStatus(status).build())), responseObserver, NotifyClientTerminationResponse.newBuilder().setStatus(flowLimitStatus()).build()); @@ -317,19 +299,13 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { - Context ctx = Context.current(); + ProxyContext context = createContext(); this.addExecutor(this.consumerThreadPoolExecutor, - () -> { - CompletableFuture future = grpcMessingActivity.changeInvisibleDuration(ctx, request); - future.thenAccept(response -> ResponseWriter.write(responseObserver, response)) - .exceptionally(e -> { - ResponseWriter.write( - responseObserver, - ChangeInvisibleDurationResponse.newBuilder().setStatus(convertExceptionToStatus(e)).build() - ); - return null; - }); - }, + context, + request, + () -> grpcMessingActivity.changeInvisibleDuration(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, + status -> ChangeInvisibleDurationResponse.newBuilder().setStatus(status).build())), responseObserver, ChangeInvisibleDurationResponse.newBuilder().setStatus(flowLimitStatus()).build()); @@ -337,11 +313,14 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ @Override public StreamObserver telemetry(StreamObserver responseObserver) { - StreamObserver responseTelemetryCommand = grpcMessingActivity.telemetry(Context.current(), responseObserver); + ProxyContext context = createContext(); + StreamObserver responseTelemetryCommand = grpcMessingActivity.telemetry(context, responseObserver); return new StreamObserver() { @Override public void onNext(TelemetryCommand value) { addExecutor(clientManagerThreadPoolExecutor, + context, + value, () -> responseTelemetryCommand.onNext(value), responseObserver, TelemetryCommand.newBuilder().setStatus(flowLimitStatus()).build()); @@ -376,15 +355,17 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ this.grpcMessingActivity.start(); } - protected static class GrpcTask implements Runnable { + protected static class GrpcTask implements Runnable { - private final Runnable runnable; - private final T executeRejectResponse; - private final StreamObserver streamObserver; + protected final Runnable runnable; + protected final V request; + protected final T executeRejectResponse; + protected final StreamObserver streamObserver; - public GrpcTask(Runnable runnable, StreamObserver streamObserver, T executeRejectResponse) { + public GrpcTask(Runnable runnable, V request, StreamObserver streamObserver, T executeRejectResponse) { this.runnable = runnable; this.streamObserver = streamObserver; + this.request = request; this.executeRejectResponse = executeRejectResponse; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java index 796d5f57af..0f353e94db 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessingActivity.java @@ -38,36 +38,36 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.SendMessageRequest; import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.TelemetryCommand; -import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; public interface GrpcMessingActivity extends StartAndShutdown { - CompletableFuture queryRoute(Context ctx, QueryRouteRequest request); + CompletableFuture queryRoute(ProxyContext ctx, QueryRouteRequest request); - CompletableFuture heartbeat(Context ctx, HeartbeatRequest request); + CompletableFuture heartbeat(ProxyContext ctx, HeartbeatRequest request); - CompletableFuture sendMessage(Context ctx, SendMessageRequest request); + CompletableFuture sendMessage(ProxyContext ctx, SendMessageRequest request); - CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request); + CompletableFuture queryAssignment(ProxyContext ctx, QueryAssignmentRequest request); - void receiveMessage(Context ctx, ReceiveMessageRequest request, + void receiveMessage(ProxyContext ctx, ReceiveMessageRequest request, StreamObserver responseObserver); - CompletableFuture ackMessage(Context ctx, AckMessageRequest request); + CompletableFuture ackMessage(ProxyContext ctx, AckMessageRequest request); - CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + CompletableFuture forwardMessageToDeadLetterQueue(ProxyContext ctx, ForwardMessageToDeadLetterQueueRequest request); - CompletableFuture endTransaction(Context ctx, EndTransactionRequest request); + CompletableFuture endTransaction(ProxyContext ctx, EndTransactionRequest request); - CompletableFuture notifyClientTermination(Context ctx, + CompletableFuture notifyClientTermination(ProxyContext ctx, NotifyClientTerminationRequest request); - CompletableFuture changeInvisibleDuration(Context ctx, + CompletableFuture changeInvisibleDuration(ProxyContext ctx, ChangeInvisibleDurationRequest request); - StreamObserver telemetry(Context ctx, StreamObserver responseObserver); + StreamObserver telemetry(ProxyContext ctx, StreamObserver responseObserver); } 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 d063b6524b..57a7b1104b 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 @@ -17,7 +17,6 @@ package org.apache.rocketmq.proxy.grpc.v2.channel; -import io.grpc.Context; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -30,6 +29,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.common.ThreadFactoryImpl; import org.apache.rocketmq.common.protocol.ResponseCode; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; @@ -58,7 +58,7 @@ public class GrpcChannelManager implements StartAndShutdown { ); } - public GrpcClientChannel createChannel(Context ctx, String group, String clientId) { + public GrpcClientChannel createChannel(ProxyContext ctx, String group, String clientId) { this.groupClientIdChannelMap.compute(group, (groupKey, clientIdMap) -> { if (clientIdMap == null) { clientIdMap = new ConcurrentHashMap<>(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index a8492b140f..1d74dc9dff 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -21,7 +21,6 @@ import apache.rocketmq.v2.RecoverOrphanedTransactionCommand; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.VerifyMessageCommand; import com.google.common.collect.ComparisonChain; -import io.grpc.Context; import io.grpc.stub.StreamObserver; import io.netty.channel.ChannelId; import java.util.concurrent.CompletableFuture; @@ -32,7 +31,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; -import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.service.relay.ProxyChannel; import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; @@ -50,11 +49,12 @@ public class GrpcClientChannel extends ProxyChannel { private final String group; private final String clientId; - public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, Context ctx, + public GrpcClientChannel(ProxyRelayService proxyRelayService, GrpcChannelManager grpcChannelManager, + ProxyContext ctx, String group, String clientId) { super(proxyRelayService, null, new GrpcChannelId(group, clientId), - InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS), - InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)); + ctx.getRemoteAddress(), + ctx.getLocalAddress()); this.grpcChannelManager = grpcChannelManager; this.group = group; this.clientId = clientId; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 9131da633d..7df45f0007 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -30,7 +30,6 @@ import apache.rocketmq.v2.SubscriptionEntry; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; -import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.HashSet; import java.util.List; @@ -54,7 +53,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; @@ -83,15 +81,14 @@ public class ClientActivity extends AbstractMessingActivity { this.messagingProcessor.registerProducerListener(new ProducerChangeListenerImpl()); } - public CompletableFuture heartbeat(Context ctx, HeartbeatRequest request) { + public CompletableFuture heartbeat(ProxyContext ctx, HeartbeatRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); - String clientId = context.getVal(ContextVariable.CLIENT_ID); - LanguageCode languageCode = context.getVal(ContextVariable.LANGUAGE); + String clientId = ctx.getClientID(); + LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); - Settings clientSettings = grpcClientSettingsManager.getClientSettings(context); + Settings clientSettings = grpcClientSettingsManager.getClientSettings(ctx); switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { @@ -99,8 +96,8 @@ public class ClientActivity extends AbstractMessingActivity { GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); // use topic name as producer group - this.messagingProcessor.registerProducer(context, topicName, clientChannelInfo); - this.messagingProcessor.addTransactionSubscription(context, topicName, topicName); + this.messagingProcessor.registerProducer(ctx, topicName, clientChannelInfo); + this.messagingProcessor.addTransactionSubscription(ctx, topicName, topicName); } break; } @@ -114,7 +111,7 @@ public class ClientActivity extends AbstractMessingActivity { ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); this.messagingProcessor.registerConsumer( - context, + ctx, consumerGroup, clientChannelInfo, this.buildConsumeType(clientSettings.getClientType()), @@ -141,15 +138,14 @@ public class ClientActivity extends AbstractMessingActivity { return future; } - public CompletableFuture notifyClientTermination(Context ctx, + public CompletableFuture notifyClientTermination(ProxyContext ctx, NotifyClientTerminationRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); - String clientId = context.getVal(ContextVariable.CLIENT_ID); - LanguageCode languageCode = context.getVal(ContextVariable.LANGUAGE); - Settings clientSettings = grpcClientSettingsManager.removeAndGetClientSettings(context); + String clientId = ctx.getClientID(); + LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); + Settings clientSettings = grpcClientSettingsManager.removeAndGetClientSettings(ctx); switch (clientSettings.getClientType()) { case PRODUCER: @@ -159,7 +155,7 @@ public class ClientActivity extends AbstractMessingActivity { GrpcClientChannel channel = this.grpcChannelManager.removeChannel(topicName, clientId); if (channel != null) { ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - this.messagingProcessor.unRegisterProducer(context, topicName, clientChannelInfo); + this.messagingProcessor.unRegisterProducer(ctx, topicName, clientChannelInfo); } } break; @@ -172,7 +168,7 @@ public class ClientActivity extends AbstractMessingActivity { GrpcClientChannel channel = this.grpcChannelManager.removeChannel(consumerGroup, clientId); if (channel != null) { ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - this.messagingProcessor.unRegisterConsumer(context, consumerGroup, clientChannelInfo); + this.messagingProcessor.unRegisterConsumer(ctx, consumerGroup, clientChannelInfo); } break; default: @@ -190,7 +186,8 @@ public class ClientActivity extends AbstractMessingActivity { return future; } - public StreamObserver telemetry(Context ctx, StreamObserver responseObserver) { + public StreamObserver telemetry(ProxyContext ctx, + StreamObserver responseObserver) { return new StreamObserver() { @Override public void onNext(TelemetryCommand request) { @@ -228,12 +225,11 @@ public class ClientActivity extends AbstractMessingActivity { }; } - protected TelemetryCommand processClientSettings(Context ctx, TelemetryCommand request, + protected TelemetryCommand processClientSettings(ProxyContext ctx, TelemetryCommand request, StreamObserver responseObserver) { - ProxyContext context = createContext(ctx); - String clientId = context.getVal(ContextVariable.CLIENT_ID); + String clientId = ctx.getClientID(); grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); - Settings settings = grpcClientSettingsManager.getClientSettings(context); + Settings settings = grpcClientSettingsManager.getClientSettings(ctx); if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); @@ -252,7 +248,7 @@ public class ClientActivity extends AbstractMessingActivity { .build(); } - protected void reportThreadStackTrace(Context ctx, Status status, ThreadStackTrace request) { + protected void reportThreadStackTrace(ProxyContext ctx, Status status, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); @@ -273,7 +269,7 @@ public class ClientActivity extends AbstractMessingActivity { } } - protected void reportVerifyMessageResult(Context ctx, Status status, VerifyMessageResult request) { + protected void reportVerifyMessageResult(ProxyContext ctx, Status status, VerifyMessageResult request) { String nonce = request.getNonce(); CompletableFuture> responseFuture = this.grpcChannelManager.getAndRemoveResponseFuture(nonce); if (responseFuture != null) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index d041039a3e..5e36c8d13f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -35,7 +35,6 @@ import org.apache.rocketmq.common.subscription.ExponentialRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.processor.MessagingProcessor; @@ -73,7 +72,7 @@ public class GrpcClientSettingsManager { } public Settings getClientSettings(ProxyContext ctx) { - String clientId = ctx.getVal(ContextVariable.CLIENT_ID); + String clientId = ctx.getClientID(); Settings settings = CLIENT_SETTINGS_MAP.get(clientId); if (settings == null) { return null; @@ -149,7 +148,7 @@ public class GrpcClientSettingsManager { } public Settings removeAndGetClientSettings(ProxyContext ctx) { - String clientId = ctx.getVal(ContextVariable.CLIENT_ID); + String clientId = ctx.getClientID(); Settings settings = CLIENT_SETTINGS_MAP.remove(clientId); if (settings == null) { return null; 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 9f155ec43b..27d4b82c4a 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 @@ -21,7 +21,6 @@ import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.AckMessageResultEntry; import apache.rocketmq.v2.Code; -import io.grpc.Context; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -30,7 +29,6 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; @@ -42,6 +40,7 @@ import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class AckMessageActivity extends AbstractMessingActivity { protected ReceiptHandleProcessor receiptHandleProcessor; + public AckMessageActivity(MessagingProcessor messagingProcessor, ReceiptHandleProcessor receiptHandleProcessor, GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { @@ -49,14 +48,13 @@ public class AckMessageActivity extends AbstractMessingActivity { this.receiptHandleProcessor = receiptHandleProcessor; } - public CompletableFuture ackMessage(Context ctx, AckMessageRequest request) { - ProxyContext proxyContext = createContext(ctx); + public CompletableFuture ackMessage(ProxyContext ctx, AckMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); try { CompletableFuture[] futures = new CompletableFuture[request.getEntriesCount()]; for (int i = 0; i < request.getEntriesCount(); i++) { - futures[i] = processAckMessage(proxyContext, request, request.getEntries(i)); + futures[i] = processAckMessage(ctx, request, request.getEntries(i)); } CompletableFuture.allOf(futures).whenComplete((val, throwable) -> { if (throwable != null) { @@ -109,8 +107,7 @@ public class AckMessageActivity extends AbstractMessingActivity { GrpcConverter.wrapResourceWithNamespace(request.getTopic())); ackResultFuture.thenAccept(result -> { if (AckStatus.OK.equals(result.getStatus())) { - String clientID = ctx.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.removeReceiptHandle(clientID, group, ackMessageEntry.getReceiptHandle()); + receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getReceiptHandle()); } future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); }).exceptionally(throwable -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index 287b1152cd..f2396b273f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -20,12 +20,10 @@ import apache.rocketmq.v2.ChangeInvisibleDurationRequest; import apache.rocketmq.v2.ChangeInvisibleDurationResponse; import apache.rocketmq.v2.Code; import com.google.protobuf.util.Durations; -import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; @@ -38,15 +36,15 @@ import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { protected ReceiptHandleProcessor receiptHandleProcessor; - public ChangeInvisibleDurationActivity(MessagingProcessor messagingProcessor, ReceiptHandleProcessor receiptHandleProcessor, + public ChangeInvisibleDurationActivity(MessagingProcessor messagingProcessor, + ReceiptHandleProcessor receiptHandleProcessor, GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); this.receiptHandleProcessor = receiptHandleProcessor; } - public CompletableFuture changeInvisibleDuration(Context ctx, + public CompletableFuture changeInvisibleDuration(ProxyContext ctx, ChangeInvisibleDurationRequest request) { - ProxyContext context = createContext(ctx); CompletableFuture future = new CompletableFuture<>(); try { @@ -54,7 +52,7 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); return this.messagingProcessor.changeInvisibleTime( - context, + ctx, receiptHandle, request.getMessageId(), group, @@ -62,10 +60,9 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { Durations.toMillis(request.getInvisibleDuration()) ).thenApply(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { - String clientID = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.removeReceiptHandle(clientID, group, receiptHandle.getReceiptHandle()); + receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, receiptHandle.getReceiptHandle()); } - return convertToChangeInvisibleDurationResponse(context, request, ackResult); + return convertToChangeInvisibleDurationResponse(ctx, request, ackResult); }); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 0aedcb54e9..6926f3d562 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -23,17 +23,15 @@ import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; import com.google.protobuf.util.Durations; -import io.grpc.Context; import io.grpc.stub.StreamObserver; +import java.time.Duration; import java.util.List; -import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.MessageReceiptHandle; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.ConfigurationManager; @@ -45,9 +43,9 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; +import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.route.MessageQueueSelector; import org.apache.rocketmq.proxy.service.route.MessageQueueView; -import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; public class ReceiveMessageActivity extends AbstractMessingActivity { protected ReceiptHandleProcessor receiptHandleProcessor; @@ -58,23 +56,25 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { this.receiptHandleProcessor = receiptHandleProcessor; } - public void receiveMessage(Context ctx, ReceiveMessageRequest request, + public void receiveMessage(ProxyContext ctx, ReceiveMessageRequest request, StreamObserver responseObserver) { - ProxyContext proxyContext = createContext(ctx); - ReceiveMessageResponseStreamWriter writer = createWriter(proxyContext, responseObserver); + ReceiveMessageResponseStreamWriter writer = createWriter(ctx, responseObserver); try { - Settings settings = this.grpcClientSettingsManager.getClientSettings(proxyContext); + Settings settings = this.grpcClientSettingsManager.getClientSettings(ctx); Subscription subscription = settings.getSubscription(); boolean fifo = subscription.getFifo(); - long timeRemaining = ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS); + Long timeRemaining = ctx.getRemainingMs(); + if (timeRemaining == null) { + timeRemaining = Duration.ofSeconds(20).toMillis(); + } long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); if (pollTime <= 0) { pollTime = timeRemaining; } if (pollTime <= 0) { - writer.writeAndComplete(proxyContext, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); + writer.writeAndComplete(ctx, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); return; } @@ -93,12 +93,12 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), GrpcConverter.buildExpressionType(filterExpression.getType())); } catch (Exception e) { - writer.writeAndComplete(proxyContext, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); + writer.writeAndComplete(ctx, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); return; } this.messagingProcessor.popMessage( - proxyContext, + ctx, new ReceiveMessageQueueSelector( request.getMessageQueue().getBroker().getName() ), @@ -121,19 +121,18 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { MessageReceiptHandle messageReceiptHandle = new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); - String clientID = proxyContext.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(clientID, group, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, receiptHandle, messageReceiptHandle); } } } - writer.writeAndComplete(proxyContext, request, popResult); + writer.writeAndComplete(ctx, request, popResult); }) .exceptionally(t -> { - writer.writeAndComplete(proxyContext, request, t); + writer.writeAndComplete(ctx, request, t); return null; }); } catch (Throwable t) { - writer.writeAndComplete(proxyContext, request, t); + writer.writeAndComplete(ctx, request, t); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java index ed7f64d32d..a8a0047c4b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -18,7 +18,6 @@ package org.apache.rocketmq.proxy.grpc.v2.producer; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest; import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueResponse; -import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -37,15 +36,14 @@ public class ForwardMessageToDLQActivity extends AbstractMessingActivity { super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } - public CompletableFuture forwardMessageToDeadLetterQueue(Context ctx, + public CompletableFuture forwardMessageToDeadLetterQueue(ProxyContext ctx, ForwardMessageToDeadLetterQueueRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); return this.messagingProcessor.forwardMessageToDeadLetterQueue( - context, + ctx, receiptHandle, request.getMessageId(), GrpcConverter.wrapResourceWithNamespace(request.getGroup()), @@ -57,7 +55,7 @@ public class ForwardMessageToDLQActivity extends AbstractMessingActivity { return future; } - protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(Context ctx, + protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(ProxyContext ctx, RemotingCommand result) { return ForwardMessageToDeadLetterQueueResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) 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 adcb364566..da37513006 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 @@ -29,7 +29,6 @@ import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; -import io.grpc.Context; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -51,8 +50,8 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; public class SendMessageActivity extends AbstractMessingActivity { @@ -61,8 +60,7 @@ public class SendMessageActivity extends AbstractMessingActivity { super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } - public CompletableFuture sendMessage(Context ctx, SendMessageRequest request) { - ProxyContext context = createContext(ctx); + public CompletableFuture sendMessage(ProxyContext ctx, SendMessageRequest request) { CompletableFuture future = new CompletableFuture<>(); try { @@ -74,19 +72,20 @@ public class SendMessageActivity extends AbstractMessingActivity { apache.rocketmq.v2.Message message = messageList.get(0); Resource topic = message.getTopic(); future = this.messagingProcessor.sendMessage( - context, + ctx, new SendMessageQueueSelector(request), GrpcConverter.wrapResourceWithNamespace(topic), buildSysFlag(message), - buildMessage(context, request.getMessagesList(), topic) - ).thenApply(result -> convertToSendMessageResponse(context, request, result)); + buildMessage(ctx, request.getMessagesList(), topic) + ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); } catch (Throwable t) { future.completeExceptionally(t); } return future; } - protected List buildMessage(ProxyContext context, List protoMessageList, Resource topic) { + protected List buildMessage(ProxyContext context, List protoMessageList, + Resource topic) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); List messageExtList = new ArrayList<>(); for (apache.rocketmq.v2.Message protoMessage : protoMessageList) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index f6f9982a59..74ef3ac02a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -30,7 +30,6 @@ import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.Resource; import com.google.common.net.HostAndPort; -import io.grpc.Context; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -56,14 +55,13 @@ public class RouteActivity extends AbstractMessingActivity { super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } - public CompletableFuture queryRoute(Context ctx, QueryRouteRequest request) { + public CompletableFuture queryRoute(ProxyContext ctx, QueryRouteRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); List addressList = this.convertToAddressList(request.getEndpoints()); ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( - context, + ctx, addressList, GrpcConverter.wrapResourceWithNamespace(request.getTopic())); @@ -98,15 +96,15 @@ public class RouteActivity extends AbstractMessingActivity { return future; } - public CompletableFuture queryAssignment(Context ctx, QueryAssignmentRequest request) { + public CompletableFuture queryAssignment(ProxyContext ctx, + QueryAssignmentRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); List addressList = this.convertToAddressList(request.getEndpoints()); ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( - context, + ctx, addressList, GrpcConverter.wrapResourceWithNamespace(request.getTopic())); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index d33f1e0a11..cc5e7f5343 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -21,7 +21,6 @@ import apache.rocketmq.v2.EndTransactionRequest; import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.TransactionResolution; import apache.rocketmq.v2.TransactionSource; -import io.grpc.Context; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; @@ -40,10 +39,9 @@ public class EndTransactionActivity extends AbstractMessingActivity { super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); } - public CompletableFuture endTransaction(Context ctx, EndTransactionRequest request) { + public CompletableFuture endTransaction(ProxyContext ctx, EndTransactionRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - ProxyContext context = createContext(ctx); TransactionId transactionId = TransactionId.decode(request.getTransactionId()); TransactionStatus transactionStatus = TransactionStatus.UNKNOWN; TransactionResolution transactionResolution = request.getResolution(); @@ -58,7 +56,7 @@ public class EndTransactionActivity extends AbstractMessingActivity { break; } this.messagingProcessor.endTransaction( - context, + ctx, transactionId, request.getMessageId(), GrpcConverter.wrapResourceWithNamespace(request.getTopic()), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java index f6a7f21b32..5fe0d1c38a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/QueueSelector.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.processor; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; public interface QueueSelector { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java index f4b4e1896e..d730d91182 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/ChannelManager.java @@ -23,7 +23,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,8 +45,8 @@ public class ChannelManager { public SimpleChannel createInvocationChannel(ProxyContext context) { final String clientId = anonymousChannelId(InvocationChannel.class.getName(), context); - final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); - final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + final String clientHost = context.getRemoteAddress(); + final String localAddress = context.getLocalAddress(); if (Strings.isNullOrEmpty(clientId)) { log.warn("ClientId is unexpected null or empty"); return new InvocationChannel(clientHost, localAddress); @@ -59,19 +58,19 @@ public class ChannelManager { } private String anonymousChannelId(ProxyContext context) { - final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); - final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + final String clientHost = context.getRemoteAddress(); + final String localAddress = context.getLocalAddress(); return clientHost + "@" + localAddress; } private String anonymousChannelId(String key, ProxyContext context) { - final String clientHost = context.getVal(ContextVariable.REMOTE_ADDRESS); - final String localAddress = context.getVal(ContextVariable.LOCAL_ADDRESS); + final String clientHost = context.getRemoteAddress(); + final String localAddress = context.getLocalAddress(); return key + "@" + clientHost + "@" + localAddress; } private SimpleChannel createChannelInner(ProxyContext context) { - return new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + return new SimpleChannel(context.getRemoteAddress(), context.getLocalAddress()); } public void scanAndCleanChannels() { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 683146f0eb..5564ca8256 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -460,7 +460,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public CompletableFuture getMaxOffset(String brokerAddr, GetMaxOffsetRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture getMaxOffset(String brokerAddr, GetMaxOffsetRequestHeader requestHeader, + long timeoutMillis) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); CompletableFuture future = new CompletableFuture<>(); @@ -487,7 +488,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { return future; } - public CompletableFuture getMinOffset(String brokerAddr, GetMinOffsetRequestHeader requestHeader, long timeoutMillis) { + public CompletableFuture getMinOffset(String brokerAddr, GetMinOffsetRequestHeader requestHeader, + long timeoutMillis) { RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MIN_OFFSET, requestHeader); CompletableFuture future = new CompletableFuture<>(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index 3b68bb00f6..acfb62a87b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -23,7 +23,6 @@ import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.remoting.RemotingServer; @@ -54,7 +53,7 @@ public class LocalProxyRelayService implements ProxyRelayService { ConsumerRunningInfo consumerRunningInfo = proxyOutResult.getResult(); remotingCommand.setBody(consumerRunningInfo.encode()); } - SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + SimpleChannel simpleChannel = new SimpleChannel(context.getRemoteAddress(), context.getLocalAddress()); nettyRemotingAbstract.processResponseCommand(simpleChannel.getChannelHandlerContext(), remotingCommand); } }); @@ -78,7 +77,7 @@ public class LocalProxyRelayService implements ProxyRelayService { ConsumeMessageDirectlyResult consumeMessageDirectlyResult = proxyOutResult.getResult(); remotingCommand.setBody(consumeMessageDirectlyResult.encode()); } - SimpleChannel simpleChannel = new SimpleChannel(context.getVal(ContextVariable.REMOTE_ADDRESS), context.getVal(ContextVariable.LOCAL_ADDRESS)); + SimpleChannel simpleChannel = new SimpleChannel(context.getRemoteAddress(), context.getLocalAddress()); nettyRemotingAbstract.processResponseCommand(simpleChannel.getChannelHandlerContext(), remotingCommand); } }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index fb2d0b091c..f5c4f3e4d0 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -40,7 +40,6 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.proxy.service.transaction.TransactionId; @@ -54,14 +53,16 @@ public abstract class ProxyChannel extends SimpleChannel { protected final ProxyRelayService proxyRelayService; - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, String localAddress) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, String remoteAddress, + String localAddress) { super(parent, remoteAddress, localAddress); this.proxyRelayService = proxyRelayService; this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); this.localSocketAddress = RemotingUtil.string2SocketAddress(localAddress); } - protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, String localAddress) { + protected ProxyChannel(ProxyRelayService proxyRelayService, Channel parent, ChannelId id, String remoteAddress, + String localAddress) { super(parent, id, remoteAddress, localAddress); this.proxyRelayService = proxyRelayService; this.remoteSocketAddress = RemotingUtil.string2SocketAddress(remoteAddress); @@ -75,8 +76,8 @@ public abstract class ProxyChannel extends SimpleChannel { try { if (msg instanceof RemotingCommand) { ProxyContext context = ProxyContext.create() - .withVal(ContextVariable.REMOTE_ADDRESS, remoteAddress) - .withVal(ContextVariable.REMOTE_ADDRESS, localAddress); + .setRemoteAddress(remoteAddress) + .setLocalAddress(localAddress); RemotingCommand command = (RemotingCommand) msg; switch (command.getCode()) { case RequestCode.CHECK_TRANSACTION_STATE: { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java index 51ff93a5e8..fde7a8af7c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/BaseActivityTest.java @@ -17,13 +17,13 @@ package org.apache.rocketmq.proxy.grpc.v2; -import io.grpc.Context; import io.grpc.Metadata; +import java.time.Duration; import java.util.Random; import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import org.apache.rocketmq.common.protocol.header.ExtraInfoUtil; +import org.apache.rocketmq.proxy.common.ContextVariable; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; @@ -53,6 +53,7 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { protected Metadata metadata = new Metadata(); protected static final String CLIENT_ID = "client-id" + UUID.randomUUID(); + protected static final String JAVA = "JAVA"; public void before() throws Throwable { super.before(); @@ -62,17 +63,20 @@ public class BaseActivityTest extends InitConfigAndLoggerTest { receiptHandleProcessor = mock(ReceiptHandleProcessor.class); metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); - metadata.put(InterceptorConstants.LANGUAGE, "JAVA"); + metadata.put(InterceptorConstants.LANGUAGE, JAVA); metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); when(messagingProcessor.getProxyRelayService()).thenReturn(proxyRelayService); grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyRelayService()); } - protected Context createContext() { - Context context = Context.current(); - return context.withValue(InterceptorConstants.METADATA, metadata) - .withDeadlineAfter(10, TimeUnit.SECONDS, Executors.newSingleThreadScheduledExecutor()); + protected ProxyContext createContext() { + return ProxyContext.create() + .withVal(ContextVariable.CLIENT_ID, CLIENT_ID) + .withVal(ContextVariable.LANGUAGE, JAVA) + .withVal(ContextVariable.REMOTE_ADDRESS, REMOTE_ADDR) + .withVal(ContextVariable.LOCAL_ADDRESS, LOCAL_ADDR) + .withVal(ContextVariable.REMAINING_MS, Duration.ofSeconds(10).toMillis()); } protected static String buildReceiptHandle(String topic, long popTime, long invisibleTime) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 79999164f4..4682c93403 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -26,9 +26,13 @@ import apache.rocketmq.v2.QueryRouteRequest; import apache.rocketmq.v2.QueryRouteResponse; import apache.rocketmq.v2.Resource; import io.grpc.Context; +import io.grpc.Metadata; import io.grpc.stub.StreamObserver; +import java.util.UUID; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.junit.Before; import org.junit.Test; @@ -41,6 +45,10 @@ import static org.awaitility.Awaitility.await; @RunWith(MockitoJUnitRunner.class) public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { + protected static final String REMOTE_ADDR = "192.168.0.1:8080"; + protected static final String LOCAL_ADDR = "127.0.0.1:8080"; + protected static final String CLIENT_ID = "client-id" + UUID.randomUUID(); + protected static final String JAVA = "JAVA"; @Mock StreamObserver queryRouteResponseStreamObserver; @Mock @@ -62,12 +70,21 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { @Test public void testQueryRoute() { + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); + metadata.put(InterceptorConstants.LANGUAGE, JAVA); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(); + CompletableFuture future = new CompletableFuture<>(); QueryRouteRequest request = QueryRouteRequest.newBuilder() .setEndpoints(grpcEndpoints) .setTopic(Resource.newBuilder().setName(TOPIC).build()) .build(); - Mockito.when(grpcMessingActivity.queryRoute(Mockito.any(Context.class), Mockito.eq(request))) + Mockito.when(grpcMessingActivity.queryRoute(Mockito.any(ProxyContext.class), Mockito.eq(request))) .thenReturn(future); QueryRouteResponse response = QueryRouteResponse.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index 15bde9918d..221fa05a7d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -33,7 +33,6 @@ import apache.rocketmq.v2.SubscriptionEntry; import apache.rocketmq.v2.TelemetryCommand; import apache.rocketmq.v2.ThreadStackTrace; import apache.rocketmq.v2.VerifyMessageResult; -import io.grpc.Context; import io.grpc.stub.StreamObserver; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -43,6 +42,7 @@ import org.apache.rocketmq.common.protocol.body.CMResult; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; @@ -92,7 +92,7 @@ public class ClientActivityTest extends BaseActivityTest { this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager, grpcChannelManager); } - protected TelemetryCommand sendProducerTelemetry(Context context) throws Throwable { + protected TelemetryCommand sendProducerTelemetry(ProxyContext context) throws Throwable { return this.sendClientTelemetry( context, Settings.newBuilder() @@ -103,7 +103,7 @@ public class ClientActivityTest extends BaseActivityTest { .build()).get(); } - protected HeartbeatResponse sendProducerHeartbeat(Context context) throws Throwable { + protected HeartbeatResponse sendProducerHeartbeat(ProxyContext context) throws Throwable { return this.clientActivity.heartbeat(context, HeartbeatRequest.newBuilder() .setClientType(ClientType.PRODUCER) .build()).get(); @@ -111,7 +111,7 @@ public class ClientActivityTest extends BaseActivityTest { @Test public void testProducerHeartbeat() throws Throwable { - Context context = createContext(); + ProxyContext context = createContext(); this.sendProducerTelemetry(context); @@ -140,7 +140,7 @@ public class ClientActivityTest extends BaseActivityTest { assertEquals(Lists.newArrayList(TOPIC), txProducerTopicArgumentCaptor.getAllValues()); } - protected TelemetryCommand sendConsumerTelemetry(Context context) throws Throwable { + protected TelemetryCommand sendConsumerTelemetry(ProxyContext context) throws Throwable { return this.sendClientTelemetry( context, Settings.newBuilder() @@ -157,7 +157,7 @@ public class ClientActivityTest extends BaseActivityTest { .build()).get(); } - protected HeartbeatResponse sendConsumerHeartbeat(Context context) throws Throwable { + protected HeartbeatResponse sendConsumerHeartbeat(ProxyContext context) throws Throwable { return this.clientActivity.heartbeat(context, HeartbeatRequest.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) @@ -166,7 +166,7 @@ public class ClientActivityTest extends BaseActivityTest { @Test public void testConsumerHeartbeat() throws Throwable { - Context context = createContext(); + ProxyContext context = createContext(); this.sendConsumerTelemetry(context); ArgumentCaptor> subscriptionDatasArgumentCaptor = ArgumentCaptor.forClass(Set.class); @@ -203,7 +203,7 @@ public class ClientActivityTest extends BaseActivityTest { @Test public void testProducerNotifyClientTermination() throws Throwable { - Context context = createContext(); + ProxyContext context = createContext(); when(this.grpcClientSettingsManager.removeAndGetClientSettings(any())).thenReturn(Settings.newBuilder() .setClientType(ClientType.PRODUCER) @@ -230,7 +230,7 @@ public class ClientActivityTest extends BaseActivityTest { @Test public void testConsumerNotifyClientTermination() throws Throwable { - Context context = createContext(); + ProxyContext context = createContext(); when(this.grpcClientSettingsManager.removeAndGetClientSettings(any())).thenReturn(Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) @@ -259,7 +259,7 @@ public class ClientActivityTest extends BaseActivityTest { String jstack = "jstack"; String nonce = "123"; when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) runningInfoFutureMock); - Context context = createContext(); + ProxyContext context = createContext(); StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { @Override public void onNext(TelemetryCommand value) { @@ -291,7 +291,7 @@ public class ClientActivityTest extends BaseActivityTest { this.clientActivity = new ClientActivity(this.messagingProcessor, this.grpcClientSettingsManager, grpcChannelManagerMock); String nonce = "123"; when(grpcChannelManagerMock.getAndRemoveResponseFuture(anyString())).thenReturn((CompletableFuture) resultFutureMock); - Context context = createContext(); + ProxyContext context = createContext(); StreamObserver streamObserver = clientActivity.telemetry(context, new StreamObserver() { @Override public void onNext(TelemetryCommand value) { @@ -317,7 +317,7 @@ public class ClientActivityTest extends BaseActivityTest { assertThat(result.getResult().getConsumeResult()).isEqualTo(CMResult.CR_SUCCESS); } - protected CompletableFuture sendClientTelemetry(Context ctx, Settings settings) { + protected CompletableFuture sendClientTelemetry(ProxyContext ctx, Settings settings) { when(grpcClientSettingsManager.getClientSettings(any())).thenReturn(settings); CompletableFuture future = new CompletableFuture<>(); 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 f243a75ce3..105ebe5559 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 @@ -40,8 +40,8 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; 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 07c6699ac2..448800e941 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 @@ -44,8 +44,8 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.assertj.core.util.Lists; import org.junit.Before; 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 6a94a02b92..a36a596e38 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 @@ -38,8 +38,8 @@ import org.apache.rocketmq.common.protocol.header.AckMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.ChangeInvisibleTimeRequestHeader; import org.apache.rocketmq.common.protocol.header.PopMessageRequestHeader; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; -import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; +import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; import org.junit.Test; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index c12bbc9c52..a5b1c5ca95 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -104,11 +104,11 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .thenReturn(CompletableFuture.completedFuture(ackResult)); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == invisibleTime), Mockito.eq(messageId), + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == invisibleTime), Mockito.eq(messageId), Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat((r) -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(messageId), + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(messageId), Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); } @@ -138,7 +138,6 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { Mockito.eq(group), Mockito.eq(topic), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes))); } - @Test public void testRenewReceiptHandleWhenNotArrivingTime() { String newReceiptHandle = ReceiptHandle.builder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java index bb147a6b0d..b9706e2af3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionServiceTest.java @@ -39,7 +39,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; public class ClusterTransactionServiceTest extends BaseServiceTest { From 15f999cd816de27db7a4dbe42549512bdc7ffcc2 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 20 Jun 2022 11:54:21 +0800 Subject: [PATCH 257/338] [ISSUE #3949] pass context in rejectedExecution --- .../proxy/grpc/v2/GrpcMessagingApplication.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index e0c06dd587..f7e3b5782e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -147,7 +147,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected void addExecutor(ExecutorService executor, ProxyContext context, V request, Runnable runnable, StreamObserver responseObserver, T executeRejectResponse) { - executor.submit(new GrpcTask(runnable, request, responseObserver, executeRejectResponse)); + executor.submit(new GrpcTask<>(runnable, context, request, responseObserver, executeRejectResponse)); } protected void writeResponse(ProxyContext context, V request, T response, StreamObserver responseObserver, @@ -358,12 +358,14 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected static class GrpcTask implements Runnable { protected final Runnable runnable; + protected final ProxyContext context; protected final V request; protected final T executeRejectResponse; protected final StreamObserver streamObserver; - public GrpcTask(Runnable runnable, V request, StreamObserver streamObserver, T executeRejectResponse) { + public GrpcTask(Runnable runnable, ProxyContext context, V request, StreamObserver streamObserver, T executeRejectResponse) { this.runnable = runnable; + this.context = context; this.streamObserver = streamObserver; this.request = request; this.executeRejectResponse = executeRejectResponse; @@ -375,14 +377,18 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ } } - protected static class GrpcTaskRejectedExecutionHandler implements RejectedExecutionHandler { + protected class GrpcTaskRejectedExecutionHandler implements RejectedExecutionHandler { + + public GrpcTaskRejectedExecutionHandler() { + + } @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (r instanceof GrpcTask) { try { GrpcTask grpcTask = (GrpcTask) r; - ResponseWriter.write(grpcTask.streamObserver, grpcTask.executeRejectResponse); + writeResponse(grpcTask.context, grpcTask.request, grpcTask.executeRejectResponse, grpcTask.streamObserver, null, null); } catch (Throwable t) { log.warn("write rejected error response failed", t); } From ebc21bb43eb1f78f56b2032bd0ab8e40f7e087a9 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 20 Jun 2022 11:34:46 +0800 Subject: [PATCH 258/338] [ISSUE #3949] Add invoke and invokeOneway --- .../service/mqclient/MQClientAPIExt.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index 5564ca8256..a174615a96 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -586,4 +586,32 @@ public class MQClientAPIExt extends MQClientAPIImpl { } return future; } + + public CompletableFuture invoke(String brokerAddr, RemotingCommand request, long timeoutMillis) { + 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 (Exception e) { + future.completeExceptionally(e); + } + return future; + } + + public CompletableFuture invokeOneway(String brokerAddr, RemotingCommand request, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.getRemotingClient().invokeOneway(brokerAddr, request, timeoutMillis); + future.complete(null); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } } From 2a089ffd39a99598d16e903a625c76c8b0775b60 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Apr 2022 11:16:31 +0800 Subject: [PATCH 259/338] [ISSUE #3906] Mark stream-related request by RequestType --- .../apache/rocketmq/client/ClientConfig.java | 25 ++++++++++- .../consumer/DefaultLitePullConsumer.java | 1 + .../consumer/DefaultMQPullConsumer.java | 1 + .../rocketmq/client/impl/MQClientAPIImpl.java | 5 +++ .../org/apache/rocketmq/common/MixAll.java | 1 + .../common/rpchook/StreamTypeRPCHook.java | 34 +++++++++++++++ .../remoting/protocol/RequestType.java | 41 +++++++++++++++++++ 7 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/org/apache/rocketmq/common/rpchook/StreamTypeRPCHook.java create mode 100644 remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RequestType.java 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 b5ba1cbceb..02f5efac2e 100644 --- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java @@ -28,6 +28,7 @@ import org.apache.rocketmq.common.utils.NameServerAddressUtils; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.netty.TlsSystemConfig; import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.apache.rocketmq.remoting.protocol.RequestType; /** * Client Common configuration @@ -69,6 +70,12 @@ public class ClientConfig { private LanguageCode language = LanguageCode.JAVA; + /** + * Enable stream request type will inject a RPCHook to add corresponding request type to remoting layer. + * And it will also generate a different client id to prevent unexpected reuses of MQClientInstance. + */ + protected boolean enableStreamRequestType = false; + public String buildMQClientId() { StringBuilder sb = new StringBuilder(); sb.append(this.getClientIP()); @@ -80,6 +87,11 @@ public class ClientConfig { sb.append(this.unitName); } + if (enableStreamRequestType) { + sb.append("@"); + sb.append(RequestType.STREAM); + } + return sb.toString(); } @@ -166,6 +178,7 @@ public class ClientConfig { this.mqClientApiTimeout = cc.mqClientApiTimeout; this.decodeReadBody = cc.decodeReadBody; this.decodeDecompressBody = cc.decodeDecompressBody; + this.enableStreamRequestType = cc.enableStreamRequestType; } public ClientConfig cloneClientConfig() { @@ -187,6 +200,7 @@ public class ClientConfig { cc.mqClientApiTimeout = mqClientApiTimeout; cc.decodeReadBody = decodeReadBody; cc.decodeDecompressBody = decodeDecompressBody; + cc.enableStreamRequestType = enableStreamRequestType; return cc; } @@ -342,6 +356,14 @@ public class ClientConfig { this.mqClientApiTimeout = mqClientApiTimeout; } + public boolean isEnableStreamRequestType() { + return enableStreamRequestType; + } + + public void setEnableStreamRequestType(boolean enableStreamRequestType) { + this.enableStreamRequestType = enableStreamRequestType; + } + @Override public String toString() { return "ClientConfig [namesrvAddr=" + namesrvAddr + ", clientIP=" + clientIP + ", instanceName=" + instanceName @@ -349,6 +371,7 @@ public class ClientConfig { + ", heartbeatBrokerInterval=" + heartbeatBrokerInterval + ", persistConsumerOffsetInterval=" + persistConsumerOffsetInterval + ", pullTimeDelayMillsWhenException=" + pullTimeDelayMillsWhenException + ", unitMode=" + unitMode + ", unitName=" + unitName + ", vipChannelEnabled=" + vipChannelEnabled + ", useTLS=" + useTLS + ", language=" + language.name() + ", namespace=" + namespace + ", mqClientApiTimeout=" + mqClientApiTimeout - + ", decodeReadBody=" + decodeReadBody + ", decodeDecompressBody=" + decodeDecompressBody + "]"; + + ", decodeReadBody=" + decodeReadBody + ", decodeDecompressBody=" + decodeDecompressBody + + ", enableStreamRequestType=" + enableStreamRequestType + "]"; } } diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumer.java index 74d6f3455f..939fb406a0 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumer.java @@ -219,6 +219,7 @@ public class DefaultLitePullConsumer extends ClientConfig implements LitePullCon public DefaultLitePullConsumer(final String namespace, final String consumerGroup, RPCHook rpcHook) { this.namespace = namespace; this.consumerGroup = consumerGroup; + this.enableStreamRequestType = true; defaultLitePullConsumerImpl = new DefaultLitePullConsumerImpl(this, rpcHook); } diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPullConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPullConsumer.java index bfeae0490e..e4643760d3 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPullConsumer.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPullConsumer.java @@ -118,6 +118,7 @@ public class DefaultMQPullConsumer extends ClientConfig implements MQPullConsume public DefaultMQPullConsumer(final String namespace, final String consumerGroup, RPCHook rpcHook) { this.namespace = namespace; this.consumerGroup = consumerGroup; + this.enableStreamRequestType = true; defaultMQPullConsumerImpl = new DefaultMQPullConsumerImpl(this, rpcHook); } 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 c7d2f848c7..33bd62b0f7 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 @@ -186,6 +186,7 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.statictopic.TopicConfigAndQueueMapping; import org.apache.rocketmq.common.statictopic.TopicQueueMappingDetail; import org.apache.rocketmq.common.subscription.GroupForbidden; +import org.apache.rocketmq.common.rpchook.StreamTypeRPCHook; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.common.sysflag.PullSysFlag; import org.apache.rocketmq.logging.InternalLogger; @@ -231,6 +232,10 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { this.remotingClient = new NettyRemotingClient(nettyClientConfig, null); this.clientRemotingProcessor = clientRemotingProcessor; + // Inject stream rpc hook first to make reserve field signature + if (clientConfig.isEnableStreamRequestType()) { + this.remotingClient.registerRPCHook(new StreamTypeRPCHook()); + } this.remotingClient.registerRPCHook(rpcHook); this.remotingClient.registerProcessor(RequestCode.CHECK_TRANSACTION_STATE, this.clientRemotingProcessor, null); 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 638d038069..bf2523c2a1 100644 --- a/common/src/main/java/org/apache/rocketmq/common/MixAll.java +++ b/common/src/main/java/org/apache/rocketmq/common/MixAll.java @@ -89,6 +89,7 @@ public class MixAll { public static final String REPLY_MESSAGE_FLAG = "reply"; public static final String LMQ_PREFIX = "%LMQ%"; public static final String MULTI_DISPATCH_QUEUE_SPLITTER = ","; + public static final String REQ_T = "ReqT"; private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME); public static final String LOGICAL_QUEUE_MOCK_BROKER_PREFIX = "__syslo__"; public static final String METADATA_SCOPE_GLOBAL = "__global__"; diff --git a/common/src/main/java/org/apache/rocketmq/common/rpchook/StreamTypeRPCHook.java b/common/src/main/java/org/apache/rocketmq/common/rpchook/StreamTypeRPCHook.java new file mode 100644 index 0000000000..7a74bc52f3 --- /dev/null +++ b/common/src/main/java/org/apache/rocketmq/common/rpchook/StreamTypeRPCHook.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.common.rpchook; + +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.apache.rocketmq.remoting.protocol.RequestType; + +public class StreamTypeRPCHook implements RPCHook { + @Override public void doBeforeRequest(String remoteAddr, RemotingCommand request) { + request.addExtField(MixAll.REQ_T, String.valueOf(RequestType.STREAM.getCode())); + } + + @Override public void doAfterResponse(String remoteAddr, RemotingCommand request, + RemotingCommand response) { + + } +} diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RequestType.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RequestType.java new file mode 100644 index 0000000000..65217d5b8d --- /dev/null +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RequestType.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.remoting.protocol; + +public enum RequestType { + STREAM((byte) 0); + + private final byte code; + + RequestType(byte code) { + this.code = code; + } + + public static RequestType valueOf(byte code) { + for (RequestType requestType : RequestType.values()) { + if (requestType.getCode() == code) { + return requestType; + } + } + return null; + } + + public byte getCode() { + return code; + } +} From b869dd111a525e912f215ff721060a65c4547153 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 20 Apr 2022 20:01:21 +0800 Subject: [PATCH 260/338] [ISSUE #3906] Add extFields to AclClientRPCHook.parseRequestContent --- .../rocketmq/acl/common/AclClientRPCHook.java | 54 ++------ .../acl/common/AclClientRPCHookTest.java | 118 ++++++++++++++++++ 2 files changed, 128 insertions(+), 44 deletions(-) create mode 100644 acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java diff --git a/acl/src/main/java/org/apache/rocketmq/acl/common/AclClientRPCHook.java b/acl/src/main/java/org/apache/rocketmq/acl/common/AclClientRPCHook.java index 9e5bf1fb5d..d4452a3f21 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/common/AclClientRPCHook.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/common/AclClientRPCHook.java @@ -16,11 +16,9 @@ */ package org.apache.rocketmq.acl.common; -import java.lang.reflect.Field; +import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -30,8 +28,6 @@ import static org.apache.rocketmq.acl.common.SessionCredentials.SIGNATURE; public class AclClientRPCHook implements RPCHook { private final SessionCredentials sessionCredentials; - protected ConcurrentHashMap, Field[]> fieldCache = - new ConcurrentHashMap, Field[]>(); public AclClientRPCHook(SessionCredentials sessionCredentials) { this.sessionCredentials = sessionCredentials; @@ -39,16 +35,15 @@ public class AclClientRPCHook implements RPCHook { @Override public void doBeforeRequest(String remoteAddr, RemotingCommand request) { - byte[] total = AclUtils.combineRequestContent(request, - parseRequestContent(request, sessionCredentials.getAccessKey(), sessionCredentials.getSecurityToken())); - String signature = AclUtils.calSignature(total, sessionCredentials.getSecretKey()); - request.addExtField(SIGNATURE, signature); + // Add AccessKey and SecurityToken into signature calculating. request.addExtField(ACCESS_KEY, sessionCredentials.getAccessKey()); - - // The SecurityToken value is unneccessary,user can choose this one. + // The SecurityToken value is unnecessary,user can choose this one. if (sessionCredentials.getSecurityToken() != null) { request.addExtField(SECURITY_TOKEN, sessionCredentials.getSecurityToken()); } + byte[] total = AclUtils.combineRequestContent(request, parseRequestContent(request)); + String signature = AclUtils.calSignature(total, sessionCredentials.getSecretKey()); + request.addExtField(SIGNATURE, signature); } @Override @@ -56,40 +51,11 @@ public class AclClientRPCHook implements RPCHook { } - protected SortedMap parseRequestContent(RemotingCommand request, String ak, String securityToken) { - CommandCustomHeader header = request.readCustomHeader(); + protected SortedMap parseRequestContent(RemotingCommand request) { + request.makeCustomHeaderToNet(); + Map extFields = request.getExtFields(); // Sort property - SortedMap map = new TreeMap(); - map.put(ACCESS_KEY, ak); - if (securityToken != null) { - map.put(SECURITY_TOKEN, securityToken); - } - try { - // Add header properties - if (null != header) { - Field[] fields = fieldCache.get(header.getClass()); - if (null == fields) { - fields = header.getClass().getDeclaredFields(); - for (Field field : fields) { - field.setAccessible(true); - } - Field[] tmp = fieldCache.putIfAbsent(header.getClass(), fields); - if (null != tmp) { - fields = tmp; - } - } - - for (Field field : fields) { - Object value = field.get(header); - if (null != value && !field.isSynthetic()) { - map.put(field.getName(), value.toString()); - } - } - } - return map; - } catch (Exception e) { - throw new RuntimeException("incompatible exception.", e); - } + return new TreeMap(extFields); } public SessionCredentials getSessionCredentials() { diff --git a/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java b/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java new file mode 100644 index 0000000000..8c0d57d624 --- /dev/null +++ b/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java @@ -0,0 +1,118 @@ +/* + * 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.acl.common; + +import java.lang.reflect.Field; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.protocol.RequestCode; +import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader; +import org.apache.rocketmq.remoting.CommandCustomHeader; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; +import org.apache.rocketmq.remoting.protocol.RequestType; +import org.junit.Test; + +import static org.apache.rocketmq.acl.common.SessionCredentials.ACCESS_KEY; +import static org.apache.rocketmq.acl.common.SessionCredentials.SECURITY_TOKEN; +import static org.assertj.core.api.Assertions.assertThat; + +public class AclClientRPCHookTest { + protected ConcurrentHashMap, Field[]> fieldCache = + new ConcurrentHashMap, Field[]>(); + private AclClientRPCHook aclClientRPCHook = new AclClientRPCHook(null); + + @Test + public void testParseRequestContent() { + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup("group"); + requestHeader.setTopic("topic"); + requestHeader.setQueueId(1); + requestHeader.setQueueOffset(2L); + requestHeader.setMaxMsgNums(32); + requestHeader.setSysFlag(0); + requestHeader.setCommitOffset(0L); + requestHeader.setSuspendTimeoutMillis(15000L); + requestHeader.setSubVersion(0L); + requestHeader.setBrokerName("brokerName"); + RemotingCommand testPullRemotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); + SortedMap oldContent = oldVersionParseRequestContent(testPullRemotingCommand, "ak", null); + byte[] oldBytes = AclUtils.combineRequestContent(testPullRemotingCommand, oldContent); + testPullRemotingCommand.addExtField(ACCESS_KEY, "ak"); + SortedMap content = aclClientRPCHook.parseRequestContent(testPullRemotingCommand); + byte[] newBytes = AclUtils.combineRequestContent(testPullRemotingCommand, content); + assertThat(newBytes).isEqualTo(oldBytes); + } + + @Test + public void testParseRequestContentWithStreamRequestType() { + PullMessageRequestHeader requestHeader = new PullMessageRequestHeader(); + requestHeader.setConsumerGroup("group"); + requestHeader.setTopic("topic"); + requestHeader.setQueueId(1); + requestHeader.setQueueOffset(2L); + requestHeader.setMaxMsgNums(32); + requestHeader.setSysFlag(0); + requestHeader.setCommitOffset(0L); + requestHeader.setSuspendTimeoutMillis(15000L); + requestHeader.setSubVersion(0L); + requestHeader.setBrokerName("brokerName"); + RemotingCommand testPullRemotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); + testPullRemotingCommand.addExtField(MixAll.REQ_T, String.valueOf(RequestType.STREAM.getCode())); + testPullRemotingCommand.addExtField(ACCESS_KEY, "ak"); + SortedMap content = aclClientRPCHook.parseRequestContent(testPullRemotingCommand); + assertThat(content.get(MixAll.REQ_T)).isEqualTo(String.valueOf(RequestType.STREAM.getCode())); + } + + private SortedMap oldVersionParseRequestContent(RemotingCommand request, String ak, String securityToken) { + CommandCustomHeader header = request.readCustomHeader(); + // Sort property + SortedMap map = new TreeMap(); + map.put(ACCESS_KEY, ak); + if (securityToken != null) { + map.put(SECURITY_TOKEN, securityToken); + } + try { + // Add header properties + if (null != header) { + Field[] fields = fieldCache.get(header.getClass()); + if (null == fields) { + fields = header.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + } + Field[] tmp = fieldCache.putIfAbsent(header.getClass(), fields); + if (null != tmp) { + fields = tmp; + } + } + + for (Field field : fields) { + Object value = field.get(header); + if (null != value && !field.isSynthetic()) { + map.put(field.getName(), value.toString()); + } + } + } + return map; + } catch (Exception e) { + throw new RuntimeException("incompatible exception.", e); + } + } +} \ No newline at end of file From 0eb4101af6233bf391e1ed096753ae4b675fb159 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 7 Jun 2022 20:14:47 +0800 Subject: [PATCH 261/338] [ISSUE #3906] Add unit test --- .../acl/common/AclClientRPCHookTest.java | 2 -- .../remoting/protocol/RequestTypeTest.java | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RequestTypeTest.java diff --git a/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java b/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java index 8c0d57d624..1dd94d8a11 100644 --- a/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java +++ b/acl/src/test/java/org/apache/rocketmq/acl/common/AclClientRPCHookTest.java @@ -50,7 +50,6 @@ public class AclClientRPCHookTest { requestHeader.setCommitOffset(0L); requestHeader.setSuspendTimeoutMillis(15000L); requestHeader.setSubVersion(0L); - requestHeader.setBrokerName("brokerName"); RemotingCommand testPullRemotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); SortedMap oldContent = oldVersionParseRequestContent(testPullRemotingCommand, "ak", null); byte[] oldBytes = AclUtils.combineRequestContent(testPullRemotingCommand, oldContent); @@ -72,7 +71,6 @@ public class AclClientRPCHookTest { requestHeader.setCommitOffset(0L); requestHeader.setSuspendTimeoutMillis(15000L); requestHeader.setSubVersion(0L); - requestHeader.setBrokerName("brokerName"); RemotingCommand testPullRemotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader); testPullRemotingCommand.addExtField(MixAll.REQ_T, String.valueOf(RequestType.STREAM.getCode())); testPullRemotingCommand.addExtField(ACCESS_KEY, "ak"); diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RequestTypeTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RequestTypeTest.java new file mode 100644 index 0000000000..7457926d72 --- /dev/null +++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RequestTypeTest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.remoting.protocol; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RequestTypeTest { + @Test + public void testValueOf() { + RequestType requestType = RequestType.valueOf(RequestType.STREAM.getCode()); + assertThat(requestType).isEqualTo(RequestType.STREAM); + + requestType = RequestType.valueOf((byte) 1); + assertThat(requestType).isNull(); + } +} \ No newline at end of file From 4db5fdf1db87d181d5e31e1eb3b57a031aea92a4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 20 Jun 2022 14:23:28 +0800 Subject: [PATCH 262/338] [ISSUE #3949] add header directly in validate --- .../interceptor/AuthenticationInterceptor.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java index 5c3969a5f4..5aa009e733 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/interceptor/AuthenticationInterceptor.java @@ -47,9 +47,10 @@ public class AuthenticationInterceptor implements ServerInterceptor { return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) { @Override public void onMessage(R message) { + GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; + headers.put(InterceptorConstants.RPC_NAME, messageV3.getDescriptorForType().getFullName()); if (ConfigurationManager.getProxyConfig().isEnableACL()) { try { - GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message; AuthenticationHeader authenticationHeader = AuthenticationHeader.builder() .remoteAddress(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.REMOTE_ADDRESS)) .namespace(InterceptorConstants.METADATA.get(Context.current()).get(InterceptorConstants.NAMESPACE_ID)) @@ -79,15 +80,11 @@ public class AuthenticationInterceptor implements ServerInterceptor { for (AccessValidator accessValidator : accessValidatorList) { AccessResource accessResource = accessValidator.parse(messageV3, authenticationHeader); accessValidator.validate(accessResource); - addHeader(headers, messageV3, accessResource); - } - } - protected void addHeader(Metadata headers, GeneratedMessageV3 messageV3, AccessResource accessResource) { - headers.put(InterceptorConstants.RPC_NAME, messageV3.getDescriptorForType().getFullName()); - if (accessResource instanceof PlainAccessResource) { - PlainAccessResource plainAccessResource = (PlainAccessResource) accessResource; - headers.put(InterceptorConstants.AUTHORIZATION_AK, plainAccessResource.getAccessKey()); + if (accessResource instanceof PlainAccessResource) { + PlainAccessResource plainAccessResource = (PlainAccessResource) accessResource; + headers.put(InterceptorConstants.AUTHORIZATION_AK, plainAccessResource.getAccessKey()); + } } } } From cf742cac0c490b92808f6a469b3ec9be3486d71d Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 20 Jun 2022 16:53:13 +0800 Subject: [PATCH 263/338] [ISSUE #3949] change ReceiptHandleGroup to msgID mapping --- .../proxy/common/MessageReceiptHandle.java | 41 ++++++ .../proxy/common/ReceiptHandleGroup.java | 54 ++++++-- .../grpc/v2/consumer/AckMessageActivity.java | 2 +- .../ChangeInvisibleDurationActivity.java | 2 +- .../v2/consumer/ReceiveMessageActivity.java | 2 +- .../processor/ReceiptHandleProcessor.java | 52 +++++-- .../processor/ReceiptHandleProcessorTest.java | 130 +++++++++--------- 7 files changed, 193 insertions(+), 90 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java index 81fcebd082..64e7a122ab 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/MessageReceiptHandle.java @@ -17,6 +17,9 @@ package org.apache.rocketmq.proxy.common; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; + public class MessageReceiptHandle { private final String group; private final String topic; @@ -44,6 +47,44 @@ public class MessageReceiptHandle { this.timestamp = System.currentTimeMillis(); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MessageReceiptHandle handle = (MessageReceiptHandle) o; + return queueId == handle.queueId && queueOffset == handle.queueOffset && timestamp == handle.timestamp + && reconsumeTimes == handle.reconsumeTimes && expectInvisibleTime == handle.expectInvisibleTime + && Objects.equal(group, handle.group) && Objects.equal(topic, handle.topic) + && Objects.equal(messageId, handle.messageId) && Objects.equal(originalReceiptHandle, handle.originalReceiptHandle) + && Objects.equal(receiptHandle, handle.receiptHandle); + } + + @Override + public int hashCode() { + return Objects.hashCode(group, topic, queueId, messageId, queueOffset, originalReceiptHandle, timestamp, + reconsumeTimes, expectInvisibleTime, receiptHandle); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("group", group) + .add("topic", topic) + .add("queueId", queueId) + .add("messageId", messageId) + .add("queueOffset", queueOffset) + .add("originalReceiptHandle", originalReceiptHandle) + .add("timestamp", timestamp) + .add("reconsumeTimes", reconsumeTimes) + .add("expectInvisibleTime", expectInvisibleTime) + .add("receiptHandle", receiptHandle) + .toString(); + } + public String getGroup() { return group; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java index 05a29c8de7..ce68fb2db9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ReceiptHandleGroup.java @@ -17,22 +17,60 @@ package org.apache.rocketmq.proxy.common; -import com.google.common.collect.ImmutableMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; public class ReceiptHandleGroup { - private final Map receiptHandleMap = new ConcurrentHashMap<>(); + private final Map> receiptHandleMap = new ConcurrentHashMap<>(); - public void put(String key, MessageReceiptHandle value) { - receiptHandleMap.put(key, value); + public void put(String msgID, String handle, MessageReceiptHandle value) { + Map handleMap = receiptHandleMap.computeIfAbsent(msgID, msgIDKey -> new ConcurrentHashMap<>()); + handleMap.put(handle, value); } - public MessageReceiptHandle remove(String key) { - return receiptHandleMap.remove(key); + public boolean isEmpty() { + return this.receiptHandleMap.isEmpty(); } - public Map immutableMapView() { - return ImmutableMap.copyOf(receiptHandleMap); + public MessageReceiptHandle remove(String msgID, String handle) { + AtomicReference resRef = new AtomicReference<>(); + receiptHandleMap.computeIfPresent(msgID, (msgIDKey, handleMap) -> { + resRef.set(handleMap.remove(handle)); + if (handleMap.isEmpty()) { + return null; + } + return handleMap; + }); + return resRef.get(); + } + + public MessageReceiptHandle removeOne(String msgID) { + AtomicReference resRef = new AtomicReference<>(); + receiptHandleMap.computeIfPresent(msgID, (msgIDKey, handleMap) -> { + if (handleMap.isEmpty()) { + return null; + } + Optional handleKey = handleMap.keySet().stream().findAny(); + resRef.set(handleMap.remove(handleKey.get())); + if (handleMap.isEmpty()) { + return null; + } + return handleMap; + }); + return resRef.get(); + } + + public interface DataScanner { + void onData(String msgID, String handle, MessageReceiptHandle receiptHandle); + } + + public void scan(DataScanner scanner) { + this.receiptHandleMap.forEach((msgID, handleMap) -> { + handleMap.forEach((handleStr, v) -> { + scanner.onData(msgID, handleStr, v); + }); + }); } } 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 27d4b82c4a..6cd6a56565 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 @@ -107,7 +107,7 @@ public class AckMessageActivity extends AbstractMessingActivity { GrpcConverter.wrapResourceWithNamespace(request.getTopic())); ackResultFuture.thenAccept(result -> { if (AckStatus.OK.equals(result.getStatus())) { - receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getReceiptHandle()); + receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle()); } future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); }).exceptionally(throwable -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index f2396b273f..7c9a664b27 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -60,7 +60,7 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { Durations.toMillis(request.getInvisibleDuration()) ).thenApply(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { - receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, receiptHandle.getReceiptHandle()); + receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, request.getMessageId(), receiptHandle.getReceiptHandle()); } return convertToChangeInvisibleDurationResponse(ctx, request, ackResult); }); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 6926f3d562..48bc1b1f83 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -121,7 +121,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { MessageReceiptHandle messageReceiptHandle = new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); - receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, messageExt.getMsgId(), receiptHandle, messageReceiptHandle); } } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index c665fe559f..3e6922b85d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -25,6 +25,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerGroupEvent; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; @@ -104,7 +105,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { for (Map.Entry entry : receiptHandleGroupMap.entrySet()) { String key = entry.getKey(); ReceiptHandleGroup group = entry.getValue(); - group.immutableMapView().forEach((k, v) -> { + group.scan((msgID, handleStr, v) -> { ReceiptHandle handle = ReceiptHandle.decode(v.getReceiptHandle()); long now = System.currentTimeMillis(); if (handle.getNextVisibleTime() - now > proxyConfig.getRenewAheadTimeMillis()) { @@ -117,14 +118,14 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { return; } RetryPolicy retryPolicy = subscriptionGroupConfig.getGroupRetryPolicy().getRetryPolicy(); - renewalWorkerService.submit(() -> renewMessage(key, v, handle, retryPolicy)); + renewalWorkerService.submit(() -> renewMessage(key, msgID, v, handle, retryPolicy)); }); } log.info("scan for renewal done."); } - protected void renewMessage(String key, MessageReceiptHandle messageReceiptHandle, + protected void renewMessage(String key, String msgID, MessageReceiptHandle messageReceiptHandle, ReceiptHandle handle, RetryPolicy retryPolicy) { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); long current = System.currentTimeMillis(); @@ -135,7 +136,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { messageReceiptHandle.update(ackResult.getExtraInfo()); - addReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle(), messageReceiptHandle); + addReceiptHandle(key, msgID, messageReceiptHandle.getOriginalReceiptHandle(), messageReceiptHandle); } }); } else { @@ -144,7 +145,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { messageReceiptHandle.getTopic(), retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes())); future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { - removeReceiptHandle(key, messageReceiptHandle.getOriginalReceiptHandle()); + removeReceiptHandle(key, msgID, messageReceiptHandle.getOriginalReceiptHandle()); } }); } @@ -154,42 +155,63 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { return clientID + "%" + group; } - public void addReceiptHandle(String clientID, String group, String receiptHandle, + public void addReceiptHandle(String clientID, String group, String msgID, String receiptHandle, MessageReceiptHandle messageReceiptHandle) { - this.addReceiptHandle(buildKey(clientID, group), receiptHandle, messageReceiptHandle); + this.addReceiptHandle(buildKey(clientID, group), msgID, receiptHandle, messageReceiptHandle); } - protected void addReceiptHandle(String key, String receiptHandle, + protected void addReceiptHandle(String key, String msgID, String receiptHandle, MessageReceiptHandle messageReceiptHandle) { if (key == null) { return; } receiptHandleGroupMap.computeIfAbsent(key, - k -> new ReceiptHandleGroup()).put(receiptHandle, messageReceiptHandle); + k -> new ReceiptHandleGroup()).put(msgID, receiptHandle, messageReceiptHandle); } - public void removeReceiptHandle(String clientID, String group, String receiptHandle) { - this.removeReceiptHandle(buildKey(clientID, group), receiptHandle); + public void removeReceiptHandle(String clientID, String group, String msgID, String receiptHandle) { + this.removeReceiptHandle(buildKey(clientID, group), msgID, receiptHandle); } - protected void removeReceiptHandle(String key, String receiptHandle) { + protected void removeReceiptHandle(String key, String msgID, String receiptHandle) { if (key == null) { return; } receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { - v.remove(receiptHandle); + v.remove(msgID, receiptHandle); + if (v.isEmpty()) { + return null; + } return v; }); } + public MessageReceiptHandle removeOneReceiptHandle(String clientID, String group, String msgID) { + return removeOneReceiptHandle(buildKey(clientID, group), msgID); + } + + protected MessageReceiptHandle removeOneReceiptHandle(String key, String msgID) { + if (key == null) { + return null; + } + AtomicReference res = new AtomicReference<>(); + receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { + res.set(v.removeOne(msgID)); + if (v.isEmpty()) { + return null; + } + return v; + }); + return res.get(); + } + public void clearGroup(String key) { if (key == null) { return; } ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { - Map all = v.immutableMapView(); - all.forEach((key0, value0) -> { + v.scan((msgID, handle, value0) -> { ReceiptHandle receiptHandle = ReceiptHandle.decode(value0.getReceiptHandle()); messagingProcessor.changeInvisibleTime( ProxyContext.create(), diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index a5b1c5ca95..bc21990c9c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -22,6 +22,7 @@ import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.ContextVariable; import org.apache.rocketmq.proxy.common.MessageReceiptHandle; @@ -32,57 +33,58 @@ import org.junit.Test; import org.mockito.Mockito; public class ReceiptHandleProcessorTest extends BaseProcessorTest { - ReceiptHandleProcessor receiptHandleProcessor; + private ReceiptHandleProcessor receiptHandleProcessor; - ProxyContext context = ProxyContext.create(); - String group = "group"; - String topic = "topic"; - String brokerName = "broker"; - int queueId = 1; - String messageId = "messageId"; - long offset = 123L; - long invisibleTime = 100000L; - int reconsumeTimes = 1; - MessageReceiptHandle messageReceiptHandle; + private static final ProxyContext PROXY_CONTEXT = ProxyContext.create(); + private static final String GROUP = "group"; + private static final String TOPIC = "topic"; + private static final String BROKER_NAME = "broker"; + private static final int QUEUE_ID = 1; + private static final String MESSAGE_ID = "messageId"; + private static final long OFFSET = 123L; + private static final long INVISIBLE_TIME = 100000L; + private static final int RECONSUME_TIMES = 1; + private static final String MSG_ID = MessageClientIDSetter.createUniqID(); + private MessageReceiptHandle messageReceiptHandle; - String receiptHandle = ReceiptHandle.builder() + private final String receiptHandle = ReceiptHandle.builder() .startOffset(0L) .retrieveTime(0) - .invisibleTime(invisibleTime) + .invisibleTime(INVISIBLE_TIME) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(brokerName) - .queueId(queueId) - .offset(offset) + .brokerName(BROKER_NAME) + .queueId(QUEUE_ID) + .offset(OFFSET) .commitLogOffset(0L) .build().encode(); @Before public void setup() { - context.withVal(ContextVariable.CLIENT_ID, "channel-id"); + PROXY_CONTEXT.withVal(ContextVariable.CLIENT_ID, "channel-id"); receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); Mockito.doNothing().when(messagingProcessor).registerConsumerListener(Mockito.any(ConsumerIdsChangeListener.class)); - messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, - reconsumeTimes, invisibleTime); + messageReceiptHandle = new MessageReceiptHandle(GROUP, TOPIC, QUEUE_ID, receiptHandle, MESSAGE_ID, OFFSET, + RECONSUME_TIMES, INVISIBLE_TIME); } @Test public void testAddReceiptHandle() { - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(new SubscriptionGroupConfig()); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(new SubscriptionGroupConfig()); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); } @Test public void testRenewReceiptHandle() { - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); long newInvisibleTime = 2000L; ReceiptHandle newReceiptHandleClass = ReceiptHandle.builder() .startOffset(0L) @@ -90,26 +92,26 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(newInvisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(brokerName) - .queueId(queueId) - .offset(offset) + .brokerName(BROKER_NAME) + .queueId(QUEUE_ID) + .offset(OFFSET) .commitLogOffset(0L) .build(); String newReceiptHandle = newReceiptHandleClass.encode(); AckResult ackResult = new AckResult(); ackResult.setStatus(AckStatus.OK); ackResult.setExtraInfo(newReceiptHandle); - Mockito.when(messagingProcessor.changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis()))) + Mockito.when(messagingProcessor.changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis()))) .thenReturn(CompletableFuture.completedFuture(ackResult)); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == invisibleTime), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == INVISIBLE_TIME), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.argThat(r -> r.getInvisibleTime() == newInvisibleTime), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(ConfigurationManager.getProxyConfig().getRenewSliceTimeMillis())); } @Test @@ -121,21 +123,21 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { .invisibleTime(newInvisibleTime) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(brokerName) - .queueId(queueId) - .offset(offset) + .brokerName(BROKER_NAME) + .queueId(QUEUE_ID) + .offset(OFFSET) .commitLogOffset(0L) .build().encode(); - messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, receiptHandle, messageId, offset, - reconsumeTimes, newInvisibleTime); - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); + messageReceiptHandle = new MessageReceiptHandle(GROUP, TOPIC, QUEUE_ID, receiptHandle, MESSAGE_ID, OFFSET, + RECONSUME_TIMES, newInvisibleTime); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, newReceiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(reconsumeTimes))); + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(groupConfig.getGroupRetryPolicy().getRetryPolicy().nextDelayDuration(RECONSUME_TIMES))); } @Test @@ -143,20 +145,20 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { String newReceiptHandle = ReceiptHandle.builder() .startOffset(0L) .retrieveTime(System.currentTimeMillis()) - .invisibleTime(invisibleTime) + .invisibleTime(INVISIBLE_TIME) .reviveQueueId(1) .topicType(ReceiptHandle.NORMAL_TOPIC) - .brokerName(brokerName) - .queueId(queueId) - .offset(offset) + .brokerName(BROKER_NAME) + .queueId(QUEUE_ID) + .offset(OFFSET) .commitLogOffset(0L) .build().encode(); - messageReceiptHandle = new MessageReceiptHandle(group, topic, queueId, newReceiptHandle, messageId, offset, - reconsumeTimes, invisibleTime); - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, newReceiptHandle, messageReceiptHandle); + messageReceiptHandle = new MessageReceiptHandle(GROUP, TOPIC, QUEUE_ID, newReceiptHandle, MESSAGE_ID, OFFSET, + RECONSUME_TIMES, INVISIBLE_TIME); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, newReceiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(0)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.anyString(), @@ -165,11 +167,11 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testRemoveReceiptHandle() { - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); - receiptHandleProcessor.removeReceiptHandle(channelId, receiptHandle); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.removeReceiptHandle(channelId, MSG_ID, receiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(0)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.anyString(), @@ -178,14 +180,14 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testClearGroup() { - String channelId = context.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, receiptHandle, messageReceiptHandle); + String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); + receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); receiptHandleProcessor.clearGroup(channelId); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); - Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(group))).thenReturn(groupConfig); + Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) - .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(messageId), - Mockito.eq(group), Mockito.eq(topic), Mockito.eq(ConfigurationManager.getProxyConfig().getInvisibleTimeMillisWhenClear())); + .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(MESSAGE_ID), + Mockito.eq(GROUP), Mockito.eq(TOPIC), Mockito.eq(ConfigurationManager.getProxyConfig().getInvisibleTimeMillisWhenClear())); } } \ No newline at end of file From f54f09d11adc03214f3d42b01afd1a9cff1d681f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 20 Jun 2022 17:57:30 +0800 Subject: [PATCH 264/338] [ISSUE #3949] return removed handle when removeReceiptHandle --- .../grpc/v2/DefaultGrpcMessingActivity.java | 16 ++++++++-------- .../processor/DefaultMessagingProcessor.java | 14 +++++++------- .../proxy/processor/ReceiptHandleProcessor.java | 12 +++++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index c3215656fc..4dac2a0031 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -60,14 +60,14 @@ import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ReceiveMessageActivity receiveMessageActivity; - private final AckMessageActivity ackMessageActivity; - private final ChangeInvisibleDurationActivity changeInvisibleDurationActivity; - private final SendMessageActivity sendMessageActivity; - private final ForwardMessageToDLQActivity forwardMessageToDLQActivity; - private final EndTransactionActivity endTransactionActivity; - private final RouteActivity routeActivity; - private final ClientActivity clientActivity; + protected ReceiveMessageActivity receiveMessageActivity; + protected AckMessageActivity ackMessageActivity; + protected ChangeInvisibleDurationActivity changeInvisibleDurationActivity; + protected SendMessageActivity sendMessageActivity; + protected ForwardMessageToDLQActivity forwardMessageToDLQActivity; + protected EndTransactionActivity endTransactionActivity; + protected RouteActivity routeActivity; + protected ClientActivity clientActivity; protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { GrpcClientSettingsManager grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); 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 59fa8afb60..3dc3afab04 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 @@ -58,14 +58,14 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class DefaultMessagingProcessor extends AbstractStartAndShutdown implements MessagingProcessor { - protected final ServiceManager serviceManager; - protected final ProducerProcessor producerProcessor; - protected final ConsumerProcessor consumerProcessor; - protected final TransactionProcessor transactionProcessor; - protected final ClientProcessor clientProcessor; + protected ServiceManager serviceManager; + protected ProducerProcessor producerProcessor; + protected ConsumerProcessor consumerProcessor; + protected TransactionProcessor transactionProcessor; + protected ClientProcessor clientProcessor; - protected final ThreadPoolExecutor producerProcessorExecutor; - protected final ThreadPoolExecutor consumerProcessorExecutor; + protected ThreadPoolExecutor producerProcessorExecutor; + protected ThreadPoolExecutor consumerProcessorExecutor; protected DefaultMessagingProcessor(ServiceManager serviceManager) { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 3e6922b85d..676527b1fc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -169,21 +169,23 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { k -> new ReceiptHandleGroup()).put(msgID, receiptHandle, messageReceiptHandle); } - public void removeReceiptHandle(String clientID, String group, String msgID, String receiptHandle) { - this.removeReceiptHandle(buildKey(clientID, group), msgID, receiptHandle); + public MessageReceiptHandle removeReceiptHandle(String clientID, String group, String msgID, String receiptHandle) { + return this.removeReceiptHandle(buildKey(clientID, group), msgID, receiptHandle); } - protected void removeReceiptHandle(String key, String msgID, String receiptHandle) { + protected MessageReceiptHandle removeReceiptHandle(String key, String msgID, String receiptHandle) { if (key == null) { - return; + return null; } + AtomicReference res = new AtomicReference<>(); receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { - v.remove(msgID, receiptHandle); + res.set(v.remove(msgID, receiptHandle)); if (v.isEmpty()) { return null; } return v; }); + return res.get(); } public MessageReceiptHandle removeOneReceiptHandle(String clientID, String group, String msgID) { From 40818f6772f1068c0fb26b22e9516df0808754fc Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 20 Jun 2022 19:35:20 +0800 Subject: [PATCH 265/338] [ISSUE #3949] set action in ProxyContext; add createForInner support --- .../rocketmq/proxy/common/ContextVariable.java | 1 + .../rocketmq/proxy/common/ProxyContext.java | 18 ++++++++++++++++++ .../grpc/v2/GrpcMessagingApplication.java | 16 ++++++++++++---- .../processor/ReceiptHandleProcessor.java | 12 +++++++++--- .../proxy/service/relay/ProxyChannel.java | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index b2581180b4..2f3c470c8c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -23,4 +23,5 @@ public class ContextVariable { public static final String CLIENT_ID = "client-id"; public static final String LANGUAGE = "language"; public static final String REMAINING_MS = "remaining-ms"; + public static final String ACTION = "action"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java index 0c13e45699..22386979a2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java @@ -21,12 +21,21 @@ import java.util.HashMap; import java.util.Map; public class ProxyContext { + public static final String INNER_ACTION_PREFIX = "Inner"; private final Map value = new HashMap<>(); public static ProxyContext create() { return new ProxyContext(); } + public static ProxyContext createForInner(String actionName) { + return create().setAction(INNER_ACTION_PREFIX + actionName); + } + + public static ProxyContext createForInner(Class clazz) { + return createForInner(clazz.getSimpleName()); + } + public Map getValue() { return this.value; } @@ -85,4 +94,13 @@ public class ProxyContext { return this.getVal(ContextVariable.REMAINING_MS); } + public ProxyContext setAction(String action) { + this.withVal(ContextVariable.ACTION, action); + return this; + } + + public String getAction() { + return this.getVal(ContextVariable.ACTION); + } + } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index f7e3b5782e..299abb31cb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -42,12 +42,14 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.Status; import apache.rocketmq.v2.TelemetryCommand; import io.grpc.Context; +import io.grpc.Metadata; import io.grpc.stub.StreamObserver; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -164,17 +166,23 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected ProxyContext createContext() { Context ctx = Context.current(); + Metadata headers = InterceptorConstants.METADATA.get(ctx); ProxyContext context = ProxyContext.create() - .setLocalAddress(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LOCAL_ADDRESS)) - .setRemoteAddress(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.REMOTE_ADDRESS)) - .setClientID(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.CLIENT_ID)) - .setLanguage(InterceptorConstants.METADATA.get(ctx).get(InterceptorConstants.LANGUAGE)); + .setLocalAddress(getDefaultStringMetadataInfo(headers, InterceptorConstants.LOCAL_ADDRESS)) + .setRemoteAddress(getDefaultStringMetadataInfo(headers, InterceptorConstants.REMOTE_ADDRESS)) + .setClientID(getDefaultStringMetadataInfo(headers, InterceptorConstants.CLIENT_ID)) + .setLanguage(getDefaultStringMetadataInfo(headers, InterceptorConstants.LANGUAGE)) + .setAction(getDefaultStringMetadataInfo(headers, InterceptorConstants.RPC_NAME)); if (ctx.getDeadline() != null) { context.setRemainingMs(ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS)); } return context; } + protected String getDefaultStringMetadataInfo(Metadata headers, Metadata.Key key) { + return StringUtils.defaultString(headers.get(key)); + } + @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { ProxyContext context = createContext(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 676527b1fc..e292bc84a6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -100,6 +100,10 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { }); } + protected ProxyContext createContext(String actionName) { + return ProxyContext.createForInner(this.getClass().getSimpleName() + actionName); + } + protected void scheduleRenewTask() { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); for (Map.Entry entry : receiptHandleGroupMap.entrySet()) { @@ -128,10 +132,11 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { protected void renewMessage(String key, String msgID, MessageReceiptHandle messageReceiptHandle, ReceiptHandle handle, RetryPolicy retryPolicy) { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + ProxyContext context = createContext("RenewMessage"); long current = System.currentTimeMillis(); if (current - messageReceiptHandle.getTimestamp() < messageReceiptHandle.getExpectInvisibleTime()) { CompletableFuture future = - messagingProcessor.changeInvisibleTime(ProxyContext.create(), handle, messageReceiptHandle.getMessageId(), + messagingProcessor.changeInvisibleTime(context, handle, messageReceiptHandle.getMessageId(), messageReceiptHandle.getGroup(), messageReceiptHandle.getTopic(), proxyConfig.getRenewSliceTimeMillis()); future.thenAccept(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { @@ -140,7 +145,7 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { } }); } else { - CompletableFuture future = messagingProcessor.changeInvisibleTime(ProxyContext.create(), + CompletableFuture future = messagingProcessor.changeInvisibleTime(context, handle, messageReceiptHandle.getMessageId(), messageReceiptHandle.getGroup(), messageReceiptHandle.getTopic(), retryPolicy.nextDelayDuration(messageReceiptHandle.getReconsumeTimes())); future.thenAccept(ackResult -> { @@ -212,11 +217,12 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { return; } ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + ProxyContext context = createContext("ClearGroup"); receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { v.scan((msgID, handle, value0) -> { ReceiptHandle receiptHandle = ReceiptHandle.decode(value0.getReceiptHandle()); messagingProcessor.changeInvisibleTime( - ProxyContext.create(), + context, receiptHandle, value0.getMessageId(), value0.getGroup(), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index f5c4f3e4d0..26ade3c128 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -75,7 +75,7 @@ public abstract class ProxyChannel extends SimpleChannel { try { if (msg instanceof RemotingCommand) { - ProxyContext context = ProxyContext.create() + ProxyContext context = ProxyContext.createForInner(this.getClass()) .setRemoteAddress(remoteAddress) .setLocalAddress(localAddress); RemotingCommand command = (RemotingCommand) msg; From e3296b8d2c63b6dca021321bd3c2d5133685251a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E6=A5=9A?= Date: Tue, 21 Jun 2022 15:08:21 +0800 Subject: [PATCH 266/338] [ISSUE #3949] Fill the field in the settings by MetricCollectorMode --- .../proxy/config/MetricCollectorMode.java | 50 +++++++++++++++++++ .../rocketmq/proxy/config/ProxyConfig.java | 20 ++++++++ .../proxy/grpc/v2/client/ClientActivity.java | 32 ++++++++++++ .../proxy/config/MetricCollectorModeTest.java | 33 ++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/config/MetricCollectorMode.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/MetricCollectorMode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/MetricCollectorMode.java new file mode 100644 index 0000000000..305ca8d28a --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/MetricCollectorMode.java @@ -0,0 +1,50 @@ +/* + * 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.config; + +public enum MetricCollectorMode { + /** + * Do not collect the metric from clients. + */ + OFF(0), + /** + * Collect the metric from clients to the given address. + */ + ON(1), + /** + * Collect the metric by the proxy itself. + */ + PROXY(2); + private final int ordinal; + + MetricCollectorMode(int ordinal) { + this.ordinal = ordinal; + } + + public int getOrdinal() { + return ordinal; + } + + public static MetricCollectorMode getEnumByOrdinal(int ordinal) { + for (MetricCollectorMode mode : MetricCollectorMode.values()) { + if (mode.ordinal == ordinal) { + return mode; + } + } + return OFF; + } +} 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 7b66e037c2..1eb3f90009 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 @@ -108,6 +108,10 @@ public class ProxyConfig { private boolean enableTopicMessageTypeCheck = true; + private int metricCollectorMode = MetricCollectorMode.OFF.getOrdinal(); + // Example address: 127.0.0.1:1234 + private String metricCollectorAddress = ""; + public String getRocketMQClusterName() { return rocketMQClusterName; } @@ -579,4 +583,20 @@ public class ProxyConfig { public void setRenewSchedulePeriodMillis(long renewSchedulePeriodMillis) { this.renewSchedulePeriodMillis = renewSchedulePeriodMillis; } + + public int getMetricCollectorMode() { + return metricCollectorMode; + } + + public void setMetricCollectorMode(int metricCollectorMode) { + this.metricCollectorMode = metricCollectorMode; + } + + public String getMetricCollectorAddress() { + return metricCollectorAddress; + } + + public void setMetricCollectorAddress(String metricCollectorAddress) { + this.metricCollectorAddress = metricCollectorAddress; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 7df45f0007..787ee61937 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -16,11 +16,15 @@ */ package org.apache.rocketmq.proxy.grpc.v2.client; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; +import apache.rocketmq.v2.Metric; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.Resource; @@ -54,6 +58,9 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.MetricCollectorMode; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; @@ -230,6 +237,31 @@ public class ClientActivity extends AbstractMessingActivity { String clientId = ctx.getClientID(); grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); Settings settings = grpcClientSettingsManager.getClientSettings(ctx); + // Construct metric according to the proxy config + final ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + final MetricCollectorMode metricCollectorMode = + MetricCollectorMode.getEnumByOrdinal(proxyConfig.getMetricCollectorMode()); + final String metricCollectorAddress = proxyConfig.getMetricCollectorAddress(); + final Metric.Builder metricBuilder = Metric.newBuilder(); + switch (metricCollectorMode) { + case ON: + final String[] split = metricCollectorAddress.split(":"); + final String host = split[0]; + final int port = Integer.parseInt(split[1]); + Address address = Address.newBuilder().setHost(host).setPort(port).build(); + final Endpoints endpoints = Endpoints.newBuilder().setScheme(AddressScheme.IPv4) + .addAddresses(address).build(); + metricBuilder.setOn(true).setEndpoints(endpoints); + break; + case PROXY: + metricBuilder.setOn(true).setEndpoints(settings.getAccessPoint()); + case OFF: + default: + metricBuilder.setOn(false); + break; + } + Metric metric = metricBuilder.build(); + settings = settings.toBuilder().setMetric(metric).build(); if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.wrapResourceWithNamespace(topic); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java new file mode 100644 index 0000000000..2fc52c6e66 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.config; + +import org.junit.Assert; +import org.junit.Test; + +public class MetricCollectorModeTest { + + @Test + public void testGetEnumByOrdinal() { + Assert.assertEquals(MetricCollectorMode.OFF, MetricCollectorMode.getEnumByOrdinal(0)); + Assert.assertEquals(MetricCollectorMode.ON, MetricCollectorMode.getEnumByOrdinal(1)); + Assert.assertEquals(MetricCollectorMode.PROXY, MetricCollectorMode.getEnumByOrdinal(2)); + Assert.assertEquals(MetricCollectorMode.OFF, MetricCollectorMode.getEnumByOrdinal(2)); + } + +} \ No newline at end of file From 374b0686a01a75e86d6002d09897fdc544148fa9 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Mon, 20 Jun 2022 20:40:17 +0800 Subject: [PATCH 267/338] [ISSUE #3949] Add README --- docs/en/README.md | 4 +- .../en/images/rocketmq_proxy_cluster_mode.png | Bin 0 -> 28027 bytes docs/en/images/rocketmq_proxy_local_mode.png | Bin 0 -> 22362 bytes docs/en/proxy/deploy_guide.md | 19 +++--- proxy/README.md | 59 ++++++++++++++++++ 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 docs/en/images/rocketmq_proxy_cluster_mode.png create mode 100644 docs/en/images/rocketmq_proxy_local_mode.png create mode 100644 proxy/README.md diff --git a/docs/en/README.md b/docs/en/README.md index 79703efbe1..e6a6d91872 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -33,8 +33,8 @@ - [Cluster Deployment](dledger/deploy_guide.md):introduce how to deploy Dledger in cluster. -- [GRPC Proxy Deployment](proxy/deploy_guide.md) -Introduce how to deploy gRPC proxy (both `Local` mode and `Cluster` mode). +- [Proxy Deployment](proxy/deploy_guide.md) + Introduce how to deploy proxy (both `Local` mode and `Cluster` mode). ### 5. Operation and maintenance management - [Operation](operation.md):introduce RocketMQ's deployment modes that including single-master mode, multi-master mode, multi-master multi-slave mode and so on, as well as the usage of operation tool mqadmin. diff --git a/docs/en/images/rocketmq_proxy_cluster_mode.png b/docs/en/images/rocketmq_proxy_cluster_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..1b4eb5eb31baca4dff805666ff6853948f0f9e43 GIT binary patch literal 28027 zcmdSBWmHvf_$|6Ojndt0x>GQE9`gy=69@!?si+{M1%W_e;MW@s1>A8N(yask zKwY)ur684~6gvf zxc7f>m)i>Rud(xCdkT-d;6kO6-S9~BS$^l{>x1fo(6Y^J@dw7WfM9E%Y> z9q74%zpy8;8Zqbgu$3#_eaW*nT40V@(J*V3ZufY9Id(Dkt}5x0x{T8BuX8_TvJn`;S-sAi-|@e0?&+wn6&em2=B@Bm zxL<4}yZ%6DdSl?wY$r4`C?I=gxAr?rU9dtYK2+-X3*I+^!OLzPc8ggyN&JqQZ86fN3SAr>;BdxV3tz zCS-Zhe&oyL!?d&DGR(1-ak*PoHQI4K;%F5{?dQ?(OHCwtus9BOF>9S|*Ru0V5=M)_}3+MxtGUA|v|r!qXMVLFx zFDVA|Ri@zHKL6`;)*!!8(YQ23(l8xI_Uuk42}Vy6Ri zsWbUrNC6=T@Hw%_#w|^h891PetueY+ZE2{g*=$Je}UxLX358KX0P2b17KWyHz`g?!q zUYmWl&a~2w0nGp%7PW9k@QJ4_h9*+FFP!*>xv8exH@p@AYYJ7QzewVK=W@1qRZU&| z`iS5OcuaiYT~IKVJ142+)2S#>)=n%0R0BciH(UreF;2O4J||8*(34 z{%M###Vn%4Lv^9BAr0VcJN^L?j%GYSA-BU}JaF{Cop+YG`K%_)q988ucs*9@=(}gI zf+y-DaXUNq<0!A-T?CIeSnI5w0>zWWw0(q7wD_x=znVWTQf)YWGZ zO|he>Bz_emN3||?F=Nrgh}URYW!@NB2lj{cR;K&XEtaejv~r@t=zUTJ*vMuQU28Ao z4{1u}I%-G0O{_;`Mn?`d5WNK}4BJ>vi$Fw+-nfCSvWZqf6JK4_nUMeiZA|p+Cv<&x zHbqTn;|pZ-B#q(|*|5gLM66%k_CetR9;)1ibJ(VLg*V&}z0R$&M#!yJu<9uRWe zl8^17Y2it)%p;bGn9y_OseSow_pK$!sZ1|8>K<s8i@Va`P(#@D|myqeXnM#)qHNTW(mF>bA7ZEUJFzfX` z>s)I;{_*rhLgCj0KX&GL1rM;Jy|0A#%4<<18(+b88)X?aS0xGI6Ifo!n41{4tNA7G z#Z`>R;Xub}VpRw#%N)gSiKVmmmdHsDJ|eSB{cy1B_zTof)ICJ%E6Hxe*F~MpW@I4%6te3c_ECL)>T)`u@Ur?6RpqZ-_%R> z&|5lOS=zT1^?&qN%5cI4nX*NTeV_g0?j8_`x}hhWmQsp@sgs@hj)`4TpnIEAr@x<6 zlukjq#Xf=!&7YiBzqpqDIOR2KnQS?4-?(^N(39s1vriV(7!FK=G9yTr2^oP9Yk+f} z-#T4-WG1QkJCYb4eNc$&?DI0wO+8^^8qS49X%MX4*J3d9F!NT3M?e+T#^R!LZ!)h` zeT3ZpHjTd9tR>?3@k4yq9K-Y`ncge2P}6yrSd3l6Q#*CZw=qJSXm})p1O7j#^Fm~8 zd9ggr^DWA%vAH9%I@)&kL{FM7?jJ5Ysjs%(C$SL4T`(bcsn%KO39LiZMT@uUw@g@d z7?M;^@X%^b@uokKm{fG=?lD6>HO!ri?nZdTkjNdH%)Wif0jq(BB$!UqpqM&{G(Y~2 ztqIq#_*eg{$CWT@tS~2I<02j1*9;WFMG^gjLJ&2dt5rmW)!ZL6*cFdlApen^0r~IZ~s1Qg6**GCWfP_^G!-Ww0UNhrWnoKzC5e;C+{$t zJ1yk(PQ_LDN@`{=;*UPb56&o`wTt#G&9<~8h)2+IEJAMn*{C4hOu*3OTC4;Wo~xqA zQehMy?FEC}noYlX+}25rHs8}t*VW;xZFHvrYi%nDK5*2V6H0qPPq`GjS z`K)@zlr**&!IfpMQyT%3wp-6Hzi2^?Cjk^c>8+*1vHjcexyRM`CS+EssPC3hzYl-W zTMR#^k8LaJZO}EnpcFuplv6clMy9Z%1+ivNVTv;%;zp8RCZ_in{tMPQivaxCRMam7 zbXJ4G9OmTPGCAb-r79Bl|6bhZtF>g;$gD{ z1W`sg9gy#Y5(JR{ULc{u{XK;Chi6&S21#1v7%Ct|iN}ETJ`J%D$}GN21^Y}W>G4er zM#b5;)|O_@PdLA7M#~_(%Gx-mrRZTFfKYE1$?|mo9^Os+O~-O>JSAy0%gP6|S@C3i zu0%~^@LA^UPov)ZR;Dg)7w5;2Rp(!gbn7YGX@PiSB46;7s@>~EP8M~T|D|&PLb}qk z{15+#vV2YlzatX8NPY&J>&}?x3FXt^%1@J96$0@@jx)NYw>PU(eUdFFzed)Pgg=g{ zT;Nb1Qhb8gC)@5Td!5igE{;`)ELp#QY8qvQjlf7HVEcj;!O7gk{E5N?2^G6moM5Kt ziOPvBlo^k}v_M?$_9YVHM-%#-IPXQoeV>KP6N!&+`z^Aebr!Nb(a5IIAEGBQn!bS! zVoNVakW^h-pBk91l^~0XI#E1soppQMDr8K(dKz#-cTF47K@=_%fq3AQqXn_ulG2~m z>)|gM=vL@GK8~*>YhD-2nR?-{@71$0+DnD`_q@UEUEa-ycfYqdJ{PCOiaLf`%Qhmv z!Z=&FjvnCWUj7^erlPJpumdT_&B3G2*Z=YMFRHs>D-k#TZ+7F4>wGIA_-?y(VxERD zE+tBJg;)=o{lI@iXj#n8IZv?YA*Df|c1R)+BM=J#)Gj8NpHzci=r{ogPH3pouRx(d z!Q2~&Bw09<TyS0!1%6Igp2>R!Sx2q_dG+Q`Jec;LWV2@c{} z8VWPv7p2RR2sx}xDKYT?(Q8D4Cn!~O9DIRaAfw_zbiVh#kAeekE%*~6?cWx`FIeFX zdcyhDf*y+=>&q&5f|i}K2m`p#{tgw4;0cN526HU%i~q~JR4v_qHQo7; zsLK5viBi~0*ltzwQV0ygt;P896Y+n!*p?vT_+7-u`p~D_D#%N~CO8)>#B|$+l!mMDr?8K6S<4cbVsYlyDf=YK$@6DbGndoAPLw$%ZRfcYtheL z!l;JekPZ?bHgoBP?Yb}>6SEox$S`KAu7i*>ZS2hv@Jr(1Bo?A!OeF{-41Ds6-%Im0;LCJ2XfRA?qcB!f za4Jaljta`q(RzjE;W=1v(Rk$xUN;KI!%oHthCZr-DT(`G$v7!k8@OjPxe)E|F zB%4r=bb(zAuogdjtg@#*pRtG?;cQ+{_$HO@u^M4dT}6!ziGwh3+aaYyKad}|<1ML! zao-0_Xavrc&*|QwY^LEu&bKul0LdA|0&&>xv#P)#oCQ&}4?VP%1OCD=Z&y1Kq@7gU z3O34=(Zh4m+l^!sDk{9mF(tN&seHZJ?Boy2fv8qtR9-e3FY!MlgRRyw{P@wj6TrgS zjU)rk+w&^_%n|-+Lou(!d(YRO*lQFnmV>cTykF-Xx_~X~e*O1&|8mjYfFYf7GcRgDDKyZYa{Pa*#RYv_=0G!3W}hOZAs^^pwM(OG_xUH|~7qUtbK4F3en zVBCt@#Y#L}!4`E*mXr~4s3;rYJYqJv<6j}p{4Y%X55IM4KXG*k-p>DhATp0fiP!|A ziBs;;OQ?r2X@9=aP7kKitaY!l^*@MTKDC$w$MLgZ<(};Wc=l8LEOqSt8lJG*=xggt z{@WqFj)Y9#i&;t$d0{6Wcv$Ky;`tkSl3HD7P`L^R`~aL8C5hc^=g(RL+|SebsFtN6 zbDp5gNg9OvzmF84qCceZUNQ+gr^Zm8jo8L^-klCx>lu4mD!fYpWKP8S=3{>wAgZc#?=0bszxGmhtr^l^AiIIVp|QfUoV_h3Q(e*Ls@ zVz!+5k)}K)VUXzm*5JopF28slq|cJ2+z1l4`?a$mqf@z*pYjdTe}2O|z?5!RoiDi_w9w-W~w!c#x>wPf}{4~9Z3;fwN##_u_A{} z`ylpU_Zgs^mMWCQ8@bIgD44HiH$Cj(LWBWJu8n@a)by`J2Pr40xlwHFlrzl(82kD7yxbF^-5C*gSZg%2? zrGm&R(((@i$p@blb3d8Jd#ftGaCbIF9mM-v-gX-097JyZ9>@o_wp=u>u(#<*l48Ph z^ofN@`mDErgwE>@hI2G7@QQ$pTm$GMoyc}ha9^{*V2Yg>_5HSdE$E9y#v@5bAP#yt zX++AB&)G=uKfH*W_h1+;pN)ySddy^|Pt{$mezKlaNdi5E?ZlP#toy8y|3&LU#wjt} zmwZ=VEytavrx+`C@rv1bvf}t7>yaf+Od{y7eEfI!Kx85`2;g_M$sI}%SjzZG$5k&E zkvNtjBDaibUJHf)-3b(Cm1>z3zqSD4^(>w;J8s9zcwN9WqM(#b6}6+nG&AaE&jQx( z=tU+~j7NsN=P2Z%4ZTDL?DT88lodaVE9Tx*^ysDVyzN$kCoU~FU3czMjCqW=W`LhC z`!1J!O=A_^*T!a5#nmFztbc)G%IPiB;!HX3*y*d0Iu1et34I2d!0!GGm-u?XXQXpD z*VooX(#R{N_E-)yjjieQ4V-~13h~OVfba#)o&T=#ZCjODNlj1sxVW z5^gC9OY-gMp2LE0v~1_mlxXXRZg0{OK-Wb6UaP^?uuvn9wVAwAtw9imGw*?%Ko#$& zpt3KHK%$AnhDVYUi4?BzrYky9VUadb29Fhn$-osz*nCJk&z)1%xa38H#j5$g(sR=% zC{AJ_dv$I(AdzP7{Ba=T9DEInbZ~bgT@vgu{dtZh3L!w3BH*91$&ao9YLk7&T4m?M z4b9A$IIhMiM7li+#bw$Z3qyl!L=yU8Ah;A z#o_zZAA`&|5Y>>+MTFC_0SmVi7e?ad>#kxXfF%4x;7v+2t3DD;fILB|U^|c&6H4RE zr>Q#GERD<0O6W95tohPEbuJhJagvf$DZ$<3^2~7b(JKBT*0Q zMTq52!DqFhhDEn|r?H5ZF|cnJse?c2CoKR{Z6zyJWa6|8)3%(KMX``x@r(vE9AL!0p;AIPXI zGr1)7q>aOPiOxVx!J?GH`;ZOKU=k>pRWOt#oy1z18ln4tzk;nl$-KB($;5m86XkQV zeu4eB$MxR=)xsDfv}KAoZDtq?q9(+~9%eQkRNvF@X)%j9<3(u?fJT@N4*;hSGQfk^oH4RXieA_Uk?=E4= zN+Zc3$l{exdF;x_Lm;UO93O2L;PESEFRQuVOBU#uGyi$Tvzc4p;@^Hi z`mH2Sc!=?TO)xb5Q%(6)x-sMKOkuJy*`(Y|)Oy;9DLOPxd_wts53YQO%ruf@I}hvs z_afwU3`F)Ltvp*n7@wrRQVmq6d(1610a9#)<>usH=`!)d|Eil>*du90nD4o0uy+mg zyswD~vK#GO>`i!DDZ?|IsHBaFiX`gLwDK``+9&VO6(EDl{+ty;r_QqJZsUo{%c3wx zR~0VRG&IvA-PU}b_E~Yk*C5SP(K|nX65$-y4{N9DSm3)%Un$*gO-_;FNe;R)xk_ld!y`uP9rgKsi*$z9ZV3&VdYnn#g-{Mr zgBA?q_CPz$?onwH7tT$v#}H9omLLXQna_Uue_zx)VU=R`QDvTvBLeS#aF6C#rEv@& zMtm38iuTwhZ~YC^26o{<5J^evT_fP54^79=jv)}JMVp4Im0aWOIi25=peY>RpcDLy z%x>S3P@V|y>>XP=%if5e?Q@JN{88{E8V#>tYt0StGyaI|aK~mFYu?`Z4v+OnZqw8dt#NYO5znD%aQa0Uq&lvBb<=DH- zH8H;nv4>6H)d(i6ziY#nR|a>YAWK*o9~zM$jwO3*5eaBI!n^GlCB0a7+~wiXv>X_e ze3f`L`&gfSzgdX$`oYz%th`At|BpaJ1eYXE<9XKOq3hkDQN2{5;Of!IqAFDG@1p#{ zV|$>EB00l7i7KGJ?ooHJDgg9dBUucx<wGH=AF;UvEdOJ&1q*4)Egz0bvK$M z1blS-Ip49CqTZW{>C+~!<#i6%IGMY17hUpt0w?|}2E`@`!nn0WsCJWruB(mTi=yeU zxwQ#iuYZ14XoSyz#Rn&fe9xb_O44uz#z(Dcb6dXJ!}U&BIxeNR$wEzz9S_-?h@H*ctbgs7OXPF=^hy-P8}R2brMZ}b+7(vl z!a1ZBz`=9}>gO6?b$-35R;d{WZ>5JQx#lonZ4WvBd2MakQt%|)E>VV@EwFUZjFn@a z^%BMZmL7`vK$6@cortI?+LA^EQf*-@J_B>Jp0E~pO*jZVUpA$Tu)l0*E_CbV(#0NZUEt1!)Z^MsE@ENH5~X; zW9c(-z8H<80=-*LT}DX0o$?pVu~!d>@^acS&Oj0>4=_=@iqxuA3Bbi%n3 z1<^PcshmtElV0{B8K}rGsOC8yCKni9%%hnw5j}FxlES2+DXN> zuYSI{67#_@y27tO^;qLWaK~l)k!4Y~pBI4UMWMwzGTm^wqMLtd#i6QsGtDlPPi{*=BjxU4Qit%p39gbG!EXST`o6UH=d#b_VLBp!W=sWWYkLF}?Q?iXBG z0h~N#hrcRm?8CGXaVgOS*-mi75Nlb8sVsv89wt0%gM|>*CFQ#*Hq#})a&62&dS-Gv zH(kU3=T-ix!oG3)mRSdgmWbjv0rG^>EJQBfZUVnN#v#GUkQFM0lca>9OG{q@Xq9$? z^ZmEDP8FkFuZfptBDO#n&YrhoxjY=M2kSI2bDlyNAJb7U`&iO*2BAR#3>O{jczNwH(~)$zq>PeykApd*sU{=Y%Ox zbjD4it-~EQU(5lKy9QJ)ePM@czoZY6deIrk*ugF!i#wUZ_XU#fASgUEFQ3d=rQ4&d zkJiMMeZ?k)wVaKLpl)_dM!x~60-Ayh7O#E-fU{vg-T0GHtLb*&g&w=g=FOob6TfRy zVkJHjcs|}*D~|d&Cu~O#Fo7{MOrrQbSRJ9p7H!^Plx{OQOPd;tdI&kI3MK>MFW!-Eo?Iy@PJ9m+F(^IP<9pqd49?l%n}2^i%FnFxcJWAxrW#;5w)GF7 z-{!tvOcf>#w;dq7OYv4H#YEh|DfErgzDF|w_Ghi!j6OJn6>s}=!I|p)aMDkWok;Q0 zXy?LXcBCC2^5OF>!ziW`iFpxRDuMHo!NP8(mI~gkz18?)33z&o?K{|#c=RmJ6&+@; z4fz`QOI^a3+Q`?M^8;AEBVU2YtYIvm`3P6fvZGQv_VpP6k=maHF<|EN24Bl}B_1g_ zs~X6G)4qvlWrZ!fV9>%j)1_AjtSm2en-I*qtb@=QNy=Vc_IiFfUdEgn-tU)qa5gb? zZ5jCQxv^tN^*$G1_Uu5g8aV`^j;eF+&?qa!0QvC4+zc41R^q{*uK(i&aHrY%$pLSV z@;=#obbYDja9ICd-X~77`OlXtvppy!cM61SrRr1vVW)hHH-r*rKc7jzIb$ixm;{Q1 zcQS*PJ_978jK#a-vajeO5{&&aNd>^Yq_NXrc_e9JDMiIDoz1B}0%FWk?LKG84&O`c z%|^?H3;ViGJ1D_gYWZFEdL0pe#PL=6G%o;A)brba-?a;0xx&T`zVvUA-4~qY-L`YX ztPJeyb>{oYHxb)_SWsCA;yU6v!01Bf4~@AJerR1VIl69 zK9@Q)S4=eQUpR;;-Rc6m6mi!U0K6pIUW&h6E6?OrAXA=H(_+C-{7XsHfP$2&;{}A3 z!^uR9{I#=(gb8uklH7K40bl zj`?my+212&QWWTH?>p^PG=63E3vK$78r`%7uSHw4m4B1^_LPv}LnBZ_j&Mv0FdP6{ z19Jkyu5V*8@YV2ltwy}Jfmc1n2G08#~|Ejl61U?ow$MT`)m zf!9vqr~QNm(onDoo~U5+hk2F?%$NqN_-5t3hZhHz_H6~9@~TXEQ@jGgLM=#t&s$H2 z*q-*9Wr7iyt?s8H_o`+|OehwEYeroXhx5cHK0Lp|%9x#Nhxhc~Rn*r2J+*n;;cY9Y zlVr=sq_L>U5h>a?Gw<+6u>OJM_+iBsb?*y$Kw4ChjGST~U^m_uiB&#@9yU4G#2_g&tN7riqDiFpA9cRY)lFGTXw)%++OW6Mz zo@ud-X#Q7o^N5>Ihy~OvJi>NSx<90!^#CUaN4j|=OASbsEu9WE{gnbxjbP~Yk^f`5 zDiB*%|UpG(vcKWpQr~U8mu`1N$U*5IBZ8T{@3LA;j#Tqp1QasXpo)KA01A6&MI$~Fz( z;jRUeH0{nqkiG zeT~3-^ITLs=VsKs9 zY%3WiV`@tDJJ9$tK$RW!y*|c;{Q-~$X|&BjMIYnvLTEFEZpMo~?N9z*Ri}7V>zj4B zEruZBQymZ-EV0G@X$bt*ercHygJ0hVLY7*$?=nurZNlLTFhIzGFImKee^e+ht+=*VRi8 z8Nx(Zrb+md8O~G<7fu8K ze*-kpU!ek*j-Ff`Ps0nOd8xOtM}C*B?VkB!UOMOjE{OS(qL*cOWbqz7;k%-g1v#|; zKoJ)SkxBj2Y4%ozs~YQ~Mu@Y~+()K&AVLpTHmydQlIOXw{LYP1;$RsxZv}Woz(Z*Q zU^9|Fa+`Xs<#Of5`IkkikbnN&W(chHCvXoyLb^hjR%cb)=@3*U4fmVyYB*iZR<^%5 zK{+iCy2^T~KFXFxuUZC# z*R6Sfu?@8dk4z3=myynHl<5UIm3deyDr~S9RuVuWmc`rwU}s0{C*HLZE5j;Kl6Vc* zfqpMmlHC5%Z66H;ItvZE)YQ8d5kVRyrb-petx|J5*gavI^}xb3(n3Sg?w7sT(vgb_ zgVB{}IK&QlDDiSjvC&dT#3w|`Dw$IQp+y|muqoZ4oDQe#p^N#0SPQr(sNOZh%{HzZRmDB^}UTo^OrS1f>3J#gc38bOw>WxLZWvWe%DWH z9D*syj@JDqZ)H8e^T(CSLEhI9Ae()^CCo3N2E=PQhUo>9?Py>w3QSleacGwzCu&i? zlUa6%Gz(}`2c`;E8A-Tep!xh;Hgo38f-tHmnevf_C=XZJ5I(}FleA=ZO;;=oen_fd zR9~B(olws^-|mQMgkQyGhTo!oM&P0DItP4F;a|h`J{@H0X0%oA1Sw~>U;LuFr;d?= zL?1G_wU^v^XZfl=e9|~7>PA|z*+w@-bfml|P!yF-V^ywU&8+PAX7rW1)V; z3;3pg)pnH)s?8CIi)&ru2pX5KvPR*yN*s`;nMXq5b=LpCcFVw(0O7H``F5GAEs0wy zlhYfYi^Ja|Evk_zC28<9A|kWweTk=f(CYr^t+%i8d-Q6t!!Ndfp!1f!NuXoe?~jYp zH+xY((IkuMj#cNq`^p$Mktu%2kGMO`X2q2~CGsBh72mos*~ac12eleE6y^hiD8$|4 zVtp8cRD+jKv6$%z;g-R}3x4diyYMp(i7Gh}?}g_b^KNy2PamJRmfiV8XH$y&jnBUj z-aGiUZ49Ye``x-_HKz2F;scO{@1>zw`Qd-w z46J{BE8WZ6v^O(iRu(TjHCWsl+iMdu6cbX#y>`DgDuqH6m>?C_m^MfOZ8pjBJrm;7 zl{nXl`AfUw7!zlbTDP+~Hyn?~x3iabY-%6T!cP{T>@KZ6#u(hrIzna&h7gm3bgLab zIO6^US*}y!=zdVYXwS%#84=2vFS!urojO09EMn8#5;BcRYitQ&mS12cM1Wb!^P9eG z$-Bs{@Etgl#G$^Lp#OA-JRRwmAJH%(S*445A=Z&6j=_D}*?)BHo}J&ZU~}scb@zDk zY>A_3IS4bbm1w|M4`RZx$_1p>RQi7KzGJXanZ4oq0}nR?FYWg8zt8L^uu$P82AF+m ze&L>7nKoL0HoA6!GUgi&Tf7fRhy|)6*ys4&XW-Kik1vz=AZb%Z4y%eB)Qz|+8PttH zwTklY=M3NVjKdp^*aFf!>WS{bx=iK|ovfxW7ucQ5IA7^{L1dtmv;m$=$BvhC zdG=T~CNgtvfZ{6GvvMIx4yo3-v8m4$f3Tl-Pr%~-0cD`nwx0TQ_vNLUVg^fBAlz|O z*T3>((?)}pU(;Hs>t|QW*wR;K|8|F(k;)t#$lDh`f_nta;_yMU_r**1aqSZ^6sIx} z+f1k+stg|lbgZ6(kLA2TRQxQx2~rR9?}Snu2+N<*xKf6SB>D*9VW_3}hrO$RMG}-` ze;HW&pd$>k^h2eHy`u>Ykrd4n9y(52bvi zfswh3mQ?Ic!Jaz1* z((n4n9ryPKQMR{<O!6v%NzTE$RZ6^U{yXGOCWg^26A+7{<-k{Hz6-= zAyWBLn5IpT>OP73Gi6zf1Hr8)k)bgra2?KIKX@61 zD5Ed%dMVXQ|H*U08+(k z=U`858)AN~FUgjZT}*;nU}5w5r*0~Jj=AVNYqsC0bxcKm=)ugOsoTJmfPE<7soI7C zA5+#8tco;7abVWY6q|)m-p5H}p|3n${ZnV41o{~MXZlYDw8f5TMhYU+k8kl}>`a4x zmmL*Qy87iHV#_E0@CnxfBxixNK%)@Ng4aSaHaDx(bA1VfCY&f{gFFnd?7E~+Xfj|*}D0WCh~k1LapPoQyxo|B49Bfy!R zdHi2XzpT=~Eqx)gtD+r+C`B|gT7aekOk!|lBXJW#Xa{^2Sh+%$bQd7R!OLkf`q&?p z9N;gM6O%lmQG#e^Ot1cyku+e|ft3frT@)JFw!r;bw(5lV0V8m*tfE0b9G9KE+5{~i z4~hP^K6_aH;@9?C?E+(&XP!Alj@N7EcWm}V^SAc~LNP%GaHDVd)go{v)Pxf0GncqO z_Om*86gnY~WC7+-IAe$wAc_>(tH=NCM9FfT*MX_~;=%;etI$sXYmbYA0JRA(+f zYtRgI5mSdo7r3o|ZkaIzhI<4MGi5kQu?P?#>H-*68C=?+PcDek=c6m$AK*fY{54NdV)75N>C|Ha2oJo&@-dLP`4D z>$EBz9C8gl8|9O@FBJ=6lYE}tdtmsIcg%TJ1SWxpT<{m6wD3pRIDDpiprkXb(1ABl zKK7kx1=S4TmFCItoolG2%S@d>jZ(*Xu0s%I$529`T5`@UF}D&L_h}K7-fI!D1Ys6OO#oR0k94;t%3;#J zS*{R#%Kl9<^>%OGx4eKp2T8IwOrw(aTMn5Iu-$WYtT7uH`(1C);R%&6sb}y~Nl^-Y znUL*LUn;;OoRs>)x*@iiiKwj%d@Hx3eLXabiVZLFuNbm4Pt5W|iD%^Ou*4zKW)z;M zBK$g!EvyO;$y-|e8K9J%KSlEts_~Dr>ARH?zCrVoym{csNTdW%i>8QP9R)Na(9)Th zRFs{7d|DF<;y?hZ6dRq^2c6ktRB9im?FgnBH4Btc66_k}8iB`%y3smGEv<9~H4_f> zgz56*oLO)-;rVJ^6G-;` zJ6bFHC9&IZFMf{|gSzH3&9M@K6!^rvu~x=}xs*QY6Pls*O(7DO1@Xqhy(x$czqteSz+Q4RS4IXDZX^xy`NlF^`z~su}@qZH+b|gjl3h z{~YuQk{%){V~hJc=ZU`W`EPlhGHs6KkH+Q^3_PEkWP$;gu_R1?Co31IR; zzn52gMaqgK`TiaDw{-k;Eo5Bf5|VI^@cyv*mm@T^d?jpnam_%x40^?}q9H2BG5fI} zfn-p57C55117vy8F<4>4MW0hhc#Af0UdNx}QFRq!;Z+CHxKQAWsRvd20h<>JI%bOQ zi-0UlW~hd7tyl-$=eD7AlsiKM4oE&Y zJVI4v>C9c6L@K-kkgDyXv=Z-ESjPld&*7L1!q`29TxNAclRW3qYWGjT1W9INl;Ut@T`ma<8 zftDwZf;NQ&>HKSG+p|?wo?e2Z)@+~sI9OksJH{#^W`a8XjbM9*_L@I(8A+WYPe(d4 zV^n38wr~M0Mb9dnZII87>$~F>5^f>hQke^z9d0z0MigLi3my zMT{zT?fRT1!&{^|rS#_DxUXYMG=2*(=uxz;das{SkaflY1d;H9DOR*+aETZvBn35k zB4(uQ8_-ga8?zO4m9Gi+2Iyjc!p|c)3*@fGw}j`lA!`;`ZZp(Oe?ZpxLP9AQ*D#@11C@b1F+TEL9tOoBIBlor&Enb~RPn(5N5^3+cMF>;2SFKh@&Rnwp zsV36QN8ZT|qk2+GK`Sex+I3f8%OjPZzb}GH`Celt<{yVZ<)3c{LOGF|vms8#OjZdH}3VG|H_;LuE=TD6&Is38LnU|0dd0CyMvUIBXyxna}VXN%Q${F>xXr z=;yP5VEkQxfLQcQT_5QgR5J4Hng1jGbq&KavXhB=9zt#rZiz3sQjm}mhtXgIoe&lS z%z4!cRm-|`QyG+3(RLhDEReUz1J982Ng8|E1eqvjMf8e&%Twx|F)%#s6rK5hRV_Z? zdXziJsB0JgTl0W~d%flV9FYkCQ*pnY$JAksaq3;_DQilz3Ax_OqtY29&!~~_UKg27 z*!?j=@}Xl}wAW?KDvP9rI5&Sy8}Dr%n%T{5(D+^Y zw>OseFo}xulLlL0v^G2E1ueGd7_kBFx9aVwzS$B-`ws8;Ap@R3K>=>QWb)bkp;Ly# z{)Z6xu4*_qn?w{#lw9t&FU4YWjkS@ei+{JU>T^ z^1(YxnnaotLKkmPc1ruE{yvpVMu2(CDk}Eyb=m7g#X3!73wO48`y5g()D!=wsXZDO z)N6dq^mA!?<>5$4om<;2Oghfv?}JDNNPi4B*a2D*RUTEbPodL%JoDL55L;^kNqkuf zA*exffg-wO^!q1M%My32O8qX2)r1~>nrWzv=bvIH9XvWdo#cMHuLatkcQ3?}1Ua9k z$$oUTn2B)KUof=SexK-ri)xumYn8Y~t#60wL#4hwfT#aLf?} z(LG<|*6m1D6d!`8I~JS_R`twkF=AU{&CjsJ8CxOlxaAc!qKmbUsFIehM*u4au%qW2 z1}&U)s~BEIE$=_eL_o!@&T}Yfzh160+w_k2W=cK1^SIiT9U>O$gW2Ji>D47jX#Ub0VAMkFFcj%!ew-+ zty2`=NNg$1(ofK~)oSoMJpCF~s1UiI{P!yk#CeT}7k#60WWoMClv7mTTUzWa!;avPDEGaRZD@oTz3m`Q1_f-a7mDcPrSS=Ac_*z>Fj*)tdNK<4CtX z(TvfUrCAVuUP>Wxn*cZaq(!sKvS@UEte+5>!wKI*`K1D2HVTj2@+BRV6{v5xD>zy4 zBC8dqJh6(cm>Ou4(0A@gZyz!8vPn%nt(tP-gq4+F;bpwLE*G?6VD_n^qk*rWAy}JL5hK+F;jX z!A6|eFe3FEy36VP63_|_&R*$UjX&JyTdaMVyNwB!T#RaX?&Yw#-Pd5r-^PY3z3$VQ zdj0mCHq6-@#X+{OtdvI#Lsa{l+H&S3o02P>!$IPHqFrRe56cv)>7oT-lou#}m#b#h zE2%Ba1db3MSGG^Lll78 z?cFka=NT%L%TC?kessjnr9Isykw5dD4~xaOaP7wpNU<_M*wq~a1V`p&X&D`M`F@0c z`!}<{#{4o=@{8PX9*O#bit@MQv0dJ%OTc$(M&@9HhC4+X$SI6DjzOTXbQC+&QuUGA z$S1TCr8`4=c9*$EmRW!6JE(fIUh4lfX3&s5EAEgLnV-rk1WO8)ZLqXVMhjh^x|r8H zyh>wM9Ze>0lS1Qm6P%JmTa+y^vt@zOae5x5VSB`8`(D=g`drQ`;|E_I{_K#C*5FbywJ4$Tf^YDxE(C64VTvE6aXb9c!2Y<23rCTbGuuf>4utf2;+ zQd&mti~Jb7JYBH=R#byCKKE(H2lhwrI}Fk01=4Fz(ssU*I7*rar6^N)$SJuidZ=D~ z1^4--p8Z=8XVmcH|EXTkbknP-d$hW?{Y=5%tzCL5agcoy*G(eSD6!>{re7+U$hyZ36R2xRA7-$<`Myt;Ri8T|8bb z)4yxY8d26KitVMbyraM}%F}PXuIv1xZOoaE6z30ZNZRjE2b3l26Vy4DdyX_2igli@ z9$g3iLF=+jUJV#hJ6QTVwm`2~eEWunqEG92C?uRl+sFp{iBS!a%&HRa+)*hDZ;vcJ z$0=1K%_c5OI*s!}R?IMr)Z6Np&Q8^Nm--`jS*Y=1y_R~JK!E;Exvo}}mf6(f&VsRF z|B38WG?%b=t6bjqb%>(!n#x2^&Elunc-OD?pkllG44MhfS<+~;X+Zu4>Gb(^ z?)Y$Rf|=dyk3!EVj|sCN~Dv5C2bF=+cx8ar6K?n@@t!tTDZ9qA2fbeDn$BU3wqOP4xyoYSRszV~K zLDcu~C?ScMeq|ADcYi*OO|{|{v1koS#274Ow1r{uC`1A9W6K(%s&Ca`+6*VP0hD-k$uDd9-8SBj3)HSc(<*fGV|GDpNzNm6D zg`(kIsxc0n6;f-D1(ndfi3j($`jdTsOdFS3B z%6pl7_sE&Jro;McqVHl+eBU5%R&8?2y-Q>|)IR4(YsII~2F7*l+0u~U;V|xEV#V*4gb5DQ=npWd1Ed_f6 z=G)|H{A2Dzxyx&CYyq!S=!)~G>h*h{>e~9o#4A3$RMS}`$%B)ctqWbj==9G}eP`A( zld3qE+#W|aG%cJ#g`WB_I$6VH@V`5V05x$^`ACk1L?j<6} zzx33(Yve9nfLW;;ZI~4VBEzt`Ea;@GLSB@qcH*|8aIa2UvmvM%_7&tACvTT7^B+gE z5=A%xPY{*>Z|~-vgB?`8lk8-+fM9ry8&`lAz6yI7yOx=;2DWN^KY5vHDV&E((hp4d zHZ%493W)y-4VFoxmRW`h(<5zY-U)z{KT$JoJ*WSky;h+YQMN-V_;1otK2O1@6zKou zyeCOyZ-x{4qX;Fh(%r!U6d6Y6#?{O@UylWOq|8^n3HNH0E{`mFyALRXR1M(UGLX+T zyHN>6!R{mr@Q_H-w=FT<{`_6sW<8LBlw}Y0EL$)76?W8&^iAN5+XCvEHxkLY^Bv0j zg<)X%nQiP6o+DAXcB*PKgMTrI1cu(mwBR_Tt_$I5$l$vKZ%kI6CU4VTaTff%ZLu91 zCD}IHb{V*=++=L=BaWT+m3UGelHBaJIQ9GB*0`sdHxyW#yWEqKh~wb=A+@Nfl1m)k z$3W4Z|EHs~jBE01peI~>Ai)#ZVOSPN4~@wRZ;3{_Ld z;<$s2)ICfi-wZUu?pZ9Y;h(3SlO?DSG_t+yQHPQtpx?}$+UpsoG>s?wh2_PWe?z3` zy+U{j6`#gQDr+k({71=tyaVRGfaend;iN*?iTLS4!=x^#L@a$KHF)MC2@AgF)4m-K zzNpJDDhDCqrPw{D-*$!c`8rZDm!{DrQ(#m*SkQ z&kP~v?%O~&71}@Wt|k}wbDQJ{R_fdtB5C}KW{NCNpSOUt4`Pi7*Bz+AnYYHn;Rb!Y z{xG&Qg4&g~{?Aru@wgrYfxZqh&f~Z3KK!d&txz~oWGhQ~36XY$^FE8^%6a^8UG85| zq}*^Cgmr}>jEL#t7fZ~XdQqQh<4A-eD;O9|=q^Y# z3u4bpPCP-p;$<)P6Z)FO6ZM`2Ho~BG{>9n8s|ZyrkJ>x(BrKSDGY3?4-kYaVbmRJYzsNGJQi@lQMGmrxbmHk<&Y9jfK)k9XP~od#Zsx|E5!+Z1LAT_sNO8n~&;3$R=8$VJ4l?4q_YkG0}~5Rh%jD4;L*q)oPU1^W>ESPSKMW&u-6yVd^;%gu){MnBjAB6!6<>aQg08D!gORy>$C(p;keq$u^bZ|8lvn;2K3lZv(7K-%YLpE~NSnmb#TR+o( zx&lV3i_4BU2$0F1^a?H#FeVs^Qonax?Iwj=r_C&f;b51i^JR z;ghkyhks^ho+tc_penPD3`sY4Ja%OabZXB6>Uun+lWPVE$cTauArpCq)&#Uw21Bq*e`(ttLAv$6PwoTC`cPcItw-5C77hPcYnzZe{9dla&*sm^ESv+RO z9x4$n%p5qLM^7dgnuJkC6NJzmnzz0VNoYet(cWuLG;^FH*r>vXv~@w$#wy_5uE*I@~;r1-8oi>>&kntwb$Xi(Q+cu{FwZ8Hk5 z2}$ydQ+WC^vE&&za)SpK|ExeBJ(h%>G#P+y>XRJ5h9 z%-KHZRiKvMTZrPsNSgH}?CkB?+L0iExhL^WfiWRQ^bY26952n0^9)DXiU3WTQ)oZx zzp#LH=wGcoKzp!s*{-k_AXadG@BTa;5!VTpO7UD4$?1KcLNQgzw^RbVz9!EisNb%2#H=8$0v~!*ZYxr0h=15f#%Jt4Jrj|+d~}s zw%Aeehd^P`4Y^kFw@tb7?B`Mt4Wf4%AQ$knBvJV&Lk!73O0QvMPSnNfT;zUmJ`^ZE z0ZXnJ^ttFqN5Kuf$egGYkyYPs8xWFnlBq0JW3vFQt|o-Lf+mH{R$`lR zK2vfi`z86c>9n_c z{8Vj(h_E(L<9=ITMj}nb@_MS>YE8{h2A#kh$&#wxHV!`JnH8lU8Y?3b6?I}}YGk9= z5uqlbV4!7S&J!g;A;aM`f*AUt1CFBeoz!zx@rCLaC{7lT)J(&7o?VIS&7t9bB+K_4 zerCJm)r%1lx?%A;vGbw8az5Q6CkaCMnRglA(-?!~O!Ne6l(50S=Lm;dNn&IXbB$H( z*M7e^*;&$<7@{&kNo|W1W1;GfCZ5yi42=(IiEJ=laOyqn`H=7^VsZ>+Ru?RFBdiHT zl*Do*NUQ=R?89{&7pGEe;!tO~l;Kw+}n z5N@es);I-vq-4!<5M56L@-JS`kDP#(hfymEiW{gO6`tM4r%Uj6`9Yj%U0aQ6aA=2pgz zOguLcx@In#q`(_sMns79ru@Ki5Q)(tPo$;va$uGzZ3}g1wNi|Tyw5N$=O*I`asWkr zYNff%XbrBjOLFsTCoGhNoMh3}q3#y3t=0b1k?FGESH4-_D_%=ij|xvFnEWzyK_ZXT zSnI*LV+OnXsjL%le-!KA8@VJKed-mIgrB}Ijm4>){XZ4t{A80F_lQmcM32cgF?-u& z>3>fr7Oyudx{r)m;X2Q}uEp6kWOzurB|Fdmd^G(R$nLUGj%>wY1tFHKnf~y?Te@dK zInXro#R4k&JV{@Q)0HT(400LdH5U>jg;)y(MSwM1*?HqjtRRFB0mF%nxRlq%B5fE- ziO#3=&LQH1(Um-4=t8_Qb30;jH8%KwbEbhvgG7B0y(&w46@aTcQ8OUG~I1k!R)@egt^{#r?|Z34tav3l4LIA`vC_IOTV ze8Qz>#+Etou}mox);IIILACX^1|+6BA&Ff@)YV&+&LF8oW04E)x4RVx zI4$`^j7NO_1vHIUe5L!82b09exQx<2Cl%E2{L-t=l#yfui^L%X|J6x#nt&ss38@w(Vkn zXUNfCF9C`&)Bg$ClU}&zDIS}U+XMaqkG))$P+BnEk8xRce;9z^dK^X%=FO>Nmbmti z(vMp^-oO3n<;eBn4Ifvge#6`%ss7`LD6_z}1{$qJRlr01D!p1IFhQ8}sc<{am;a;P z7FXyiwn0F zB-Gn@z@@{xgTAMt_HqvJMJQpLmt89MY>DDDe~of;gm43@+05gF7+kYGM`4^q$NT9! z4wCw^DkMv%r#;sRzJ1QW48nVAP%}mR-f5$T;VMsuB(to!i}L22s~n_H6xy}e9dEw3 ze|PH~q97G0s*@?~20`Cs$qyG6GP(yEva+Lbgp^_uiTd|6-rh>jYR3z%f2S@tpwY(Z03Sx+!$6VK%G1__&$;MRY!^!cRBWPos~ z?&;$1*9T3?v~dCTX{yf`>gY)PzM#}D*Ivgpicumc3#K6@L_NlJjhX-HWb?popP2pq z-kK8(zq?-7=RGe>{LV0p=%ZJpn_nwo=Pe+AoLvvN7WVOEmUS?tDdf8 zsTtNj$6c;;bTzjuwI);DU6c^buv^SXS0X1!+O zG+h)w$U1YX1B=uKA%(yOMcuRZWf^13!=Aaemz!xcW;1|+eA!dFAg-mDe8-3P6||wp zBP>a5zjQ^#R^v!&=@A5RrWo=HtB9u70a{sUR+Q>7&dGPFti7KIZLl}|Cj`jPx&0qY zDb&SDHKc-Q?{k5kdj{XAXK#1n*KRJ3oB{l}AvaeH7k-1MR5gbcwVAJBS`|kXQ<*2T zYUn|BrdS*Pm@F+(ypo+LiG-g-+(3bvG>Ztnc#OWwCiqe#tRs!rZ8$nnJ`?RHx=)k| zxVa#p-Hmz58RFbNd+!L$O?llIIXEwB*bAX7lq%i;-=cZ|bQf7bd{LUzKl@+Ym^llE z5o&Kbb^pQmnaM7|iJ|%cXMA#Nc}f&fGP6#zc0n(+DLLco&)FMzFs6)=~l`OUUL0|A};8ke;o6!Rc%s3DG-E_ z*6efX`>fPcEh?Vo>-Z5sIPUVN)Af!}13hR;*LamjEt0q%y+(}|pL;WrUBFc%jk??^ zs-#v=joFX5lcJr+0pP;&Q_4U00%o~RK&Qm6xT>w4$~z%k0uipjJc?kpSxPxzpWAD` zdJ%}F>FGGTm3|Bae`ZKqC)LhD_<_1z!!sKB6^#B5&2~~{%c?t@R!ITMc#Y;)qu9^4 znG8i9hZwfq=*JZP#`7L{^LJ-}mOw{NG4cRwDa@h?P48nt@wgQ}t;n^CNAp?$nb99| z_Ri;z!)ld5yhzji(PeEA=}9t24uC~#{46tAWDOk9r7z+Dub{)m0`d{%Ti~d!_j~j$ zK};#iq(h$nr#nM&T9i8SxpC*?r?cu6-iS0qvNq_D6IXhG)-8x_PR1`bqG>+*Sv{o# z#(l1PXhk(CT1MOD=g{R?UY3^f%gNUQVnSYP;>2w!~`n}~bCtODXKZ$+eKo$#mod)h`l^T{Ckr#ET7p0sVD+WGH* z&f?6o|7dF~N;f%TbkP#9{VE!^fhLBY+JD|TN7!6QWrVYoJNXyB{eJX^a`$DWrI!-p z7e3tN^P9`<1aH9$ZY-U_Bhr`cv}sv_G(`c^m_)9zsXHU>?{o+oVnAjGE{x#FAdMhr z!X2NSNUBvmmCKD^{@E1Pl>li*a!QfRYVYrhWTliVQR)QHM! z(;OxGL>ZP;I*}wy)AY{N`)|}5(Cq*cDatO$0ZZQL2QAhXpsc^@DI6yLzI>@!SM(s} zoCl&$OacNJy-9v{$@Op$SmGN)$>~)SGqI)vgyLht=gp`H;X}KW@-N}&2elz@Z>J3P z5+gbXnm=?yfj-ulZ329{rFXhXVnVYFRZrNeBf*>$sTsT4yC$eD=%KXi!|>PQ42ezz zQ@6^^6jrXo!~JZ`*S4i z31PW#tU9qi3r5(NJz8Q9UCp?2*ZZdwaFGBV{*Hj>4YR~o3b(Sq6-h-xrAo8y36zMv z4OT7OYBUm!H#m+f`@plugWT_-5P1tKenLd0HDV3$Q_oO;iwLle5y-SwI(QEstg+1_ z0uC@i8%bKBdtA4q4Sxebcd70}C+sm`oTZ&|k5~D#lO(~YBw}9!2%Cu`D2EAX#X|i< zH*#)~;u+aG|5}jkb%C3=%m>;4BfX{$!wA)RHv|0EJ^SH#E|g2C3i{*>4j}NS*&AuV zp&sp=pa0!l-9MAId$?w1vuxlSx}#m%B|(|@s7#fy&7-kSaT+^ABL7uuH+o@)fUg;e zvcfwe8i9O!EJrs6m+|NUWFD85ghUnzBW}UOrse==ZKhbuel4F|kuWS3XE;@?ffW!Q z0Czr<1aCMF+0B+OE6OTZceJECjL125jfn5*FnmU-PgFN~se?WTfIFGBPTwf-cW{b|2P&iSgw`eaz<0R_uJ`&VoRAN3X%$HG1NDsQ3bRW@pSk?9zp8ObNBEail&;f!@rq5I7k4pLVnn;Tbc_U0 zBrD|G!Af`)QGVs31*1^=DYdh;*<=|)wf=GfOyX-3c!CV%&>xc07(?-~54+o2Q=lu8 zL5e}0V9=P%B*v~ARA<%ZDb2$FjC^6V9S)D%Yx67^BZ)X2##Jj7*-qES|$1M zfKZ&$??<0oo3ChLlTfU!9q;M_u8-TYi%He>h?_yy*F zboH$`CB>b4gfbeA%iW{Geje|?|9Oc0OTk=d3UBq$>%!f_STCPfc}zpcfCuON=m;C1 zm`e5@!nXb5vBw1qA3ZoytEZD&go(yf46LH*ZphSTCXZ0+@@NeGC-hcoUl{=l%Lg=iK|C>9^sFpO(sF*@PqtD9*%Q248fTrS+eQ3 z1iy(^d*#M{W%l!qFzZ%;-*s!+l8}gJME7c{bvgPwwoe(u8GhQ!xR7BedBaT0)N8wn zcqP?idwrH(UFzsCx@UYky8D@UuONj^LE#*$%Q}s+XxN3uKm5h)a$6uoEzXJ<{MJN7 z(@TVb;`Q~ow&sFeaS2nD#U?s9kRguT*)VO$-er3+tX|x{%3nj*F{iE|BNMc~8w`zN?NBH2 z6(gwC;3*VVLVoC*Q}y^av;TD|A*O(w*z7d+nWKceNbtQ_!f%vA{V`8M=yX$r?iPc0 zn4SljL@g+4UjA6O%$I6pTQ}O^D)GS@l(ZAe0=wP!kC-D&W+>Co&RZ*)Sy$|m3In#+ z$8ndjL(KA9Z=J9;-ie+#5q~Po>DvRE#A@Yq3JmgwHLlYR#U6$ABFtlvj5BhJoUUJJ zy3M6L#=V#RuT1YYI6lW~&M=Bxv$Q(e2I6pAjy@0e_KnsW9c|!r~ zMo1!QS`$By5vzwQ97PfF?C&BpWPBlcCwvb+J8e6oA<<79UW56eDT2+()0}B%KheD! z);HAV-;$%i^M*|9Nso0FbOgvxlUi{}gtzFgodF+^ol4xw$4QS;S-B4tnO>MbT7TBM zP@w5pi@1N=!%nWYhb;WO240}_`<=-fcP0$Br}UWD*Mqmk1ZvRqB!mV$Dk85`v|Qg4 z*RlT^Mj{XRW(C;wFX_1R6EWuKuHjs-re7O*Jmva_!clMf^%`losyE_TTZUjR7J!&p z`<3|k%gIv^^1XV&m^Ws+hq~`wDou=#J3%cUS>&X!GHLehPCw!R#j1SVK8v2J?~~hE z(*Cp{{T44oSWnW}QdFor<+3C*&YeAxK%&-64NE@zwd>36?2VqC-E3t+U}W^lNnWyT zY{sWt2zP_IB)$@c24`-@GfUl55(?7GP!k~UyVYD`yQrxb*NM{Hk>cbGPkM6xlNE$| zvTIzN+Pm$gkoPf(^x4n9!{pc~5VNfiv*6^sCuTc*V~ENcO8&~Nvh?3rH>p@z%M5bo zrscn-COhzeVflONJv7;2hcMd%L`v0oKt=bbLz@{3r60FGKY`S zR%FNMUB!O^zp&fb8H5#t$#QVE%AB^V{v%y1_YH z5-iEb0DB(nS`ol&LG8sl*WX1k}xI(UcqOCQ`lJNl-)YCoL=n@;~kP0Nb zN$HpuJO>R3hmVSae7kOeAV53$pi>0|D%J<@+Rll1r+Lm5dxK)w9b9ufdH2>YM zVoz=TujwL9Ladh&y8ti*Kp>&j#d1~$TTrM|fOE;bwXFYW~Iu&7#Wyo#r=dVGDN6BFa~>aM_P zmHfC^fJ$=dSG4T$>DQQPPSv^ggbV8`s+{etgIY7#csGdgSt1*KOU%WBZt)KkfG5N_ zh5q^EztUG@K!x000;>^*E&MV^DOBCl(g!0Eyy7KVm}rb+ra2~t+u7hX;DryX<8dK5 z{?2QCm3i3EaW!UC8c5E=O-^VaI7mTyIZjB}9U9b1O7IgVPU(ENcZ0SejO#kjLosdl^QF`H|z2q+EI zy&vxfhGQJ}+Gp*xp7lI)&S&lusiGu}fl7i30|SF0D$)kMNvwU!)d(+c1)b{DbfamPsVEDeE)!sk>4(Y(LKmoEAEKCGsE@U`c6DkDcVEA`y z;(=o-5Hc(j@G7Gw}IpToMnd7BzVLPK9C?}rUaN*XGDY%(GoWbmK1^~3ag zF8TL*cSjBZ*?CvrK4CE0=EIZFM)S?4OkO(Im3&;FjEDku%q8JJTxP z?^80qS`;&)RVN}yA=!~1-{ z@|?%Yo3Ej%P3L#Nu%ZM8*xc<(i_N>-Z+u_vtrg&)tM&R5ZID9uneyp0+$z&Njo5v` z$9p-;raH5_`)>boH3X}qRP1q2WNG83=h;uk_0N0U)WaC=@eG*U6TcH5?R|*%LDdwq z!C6$^vA)Njsl4mPOE7@Zu6fR4?>id%Hz5&!EX){mt@nujfwtyguo(8#|_95@Mv-UikM@oi7744jm+PA){>O3FuvlF_CBngEf zD?mfVj6p;8M#|<|`?h)FIV3c=3ndcS?O{H)gHM;Y!3 z-)(M&?)!bMo~$z4$D+#WcBZO^alzZP6Q7m)$uHp)^Aih0UBU41TVRH!lgs}1M|)a5 zcN#j5eTbxdNygXg0k`rxo@=2~$@vePvNbM-VT(PFM-F>#H9q=jRCf}2(f+rihS$Cw z6$l&j4Ees!nwiZj{`XQwQz^(*7!ThGyAxv1c1I1LoV|aLE}v$2P(3cXFWBvQP52mi zUsW3BZf84m=dEzFp<`Yq!;1uAB*5~5Sz6!yZRyrnpiu4S93o2|7ud-;L}Y4Qa$hJ0 zf2>`H=Iq&96wm;fTJ|{+8TAM!cmL=OeWr|0kN<|mls@IUY2MvV1myJ{gtGe@cc+Pz zliyOTs=)ian$Wc_FFr3WA|BKc|JMtTwJF~B*6?AS5O+fBi@lfQN!QJ`XF>$Oo(r!s7}wP9%VPFozV5Twu1;$`T(VteWN$c9P72Dq-{F&t zr8!B(vefS- zC848~fP*w-^xxu$3HXA?ts9fvd1o;!BCuFgsu6hqvSvH!k(sE4jitY{Bbg8G4~ZN* zb#>Z9=Szy*jznrb=8|`jBm6S!^8>e8p7(xvTi@b_rmwvzGk3zPxdLe5%;7)Y&Gv{s zp9oI=7QXnE{P&}2>}9NjFOA=kjp1kj4KHppZsYxN$BxD$SZaSAzpI%BScoLwTIJOppG>A82mbau^#Hj^ z!RNT`Q~O4o&?FohOM(VN9*=M@TK{iF{c{nNQGscl3Op6*p4%}8`p%C_-7YzlWV?jW zM?r~MtS&<4{VXWB9zipiC{2-xe4p#Fe47DDLt|^DvTNH)v#M(PJ0jsui{p+m!C1+u zu|C3Fqu>y5zc97vGLfsbZ^F>N`!$-rh*TnMM!bviaaWp{3{~Xe^v7J7@s@{vi~5`2 z%f1(5+K=#gq_(vZ-T0?w9j{V7DR&C(Jz@A|+||`j^cHtQm5av$Kq{T;yco}3TG80E zFHY4Qu_D@fgwd*DGHrQ?ya<8M<^TN#@^ds%V2sr5w*>NxGvV(H+vNA1dH#2M+NhiY z&mfVSqlDp6S(tM%;nwUwHGS_nvU8B%$@4kxH+S&A$mX`h_ul;yUT-}U-C?jGLq07w zIR%3BD)Jt66PNaMs_s2!V4LSUFf`w9%*}lH$pUofT0@ht2cWmA0eCrE@0H ztmmIJuHZffV@Ai8H#e+*UhRbu08={+%s{6ly+*5uR!0o-qhExcGT#ixBH~_Hyl=I$ zh5>#Cv48TPA9gyKPU?mzyn-WUIQtazaAzEBYP#GPv=}4~Yky#B`|&?NTr>>rpZ>s7 z-pTba5M2=wJ5P+??3qiu1{LhV12)^*RzYpKeMgodH$}OIyPZp1t;!yp1W4K0-NeKdUzETMB#ZUa$hBHzI858f~8xnJ**#9>Rb?eI*WhE z9@a`nuzJ5^{3R+wQdqo9M<-}sN=_BQrXEJZh+(j}@m+@uta^-fzk`@ipx@AATj!ht zQ8U_`HQ1Avv%(X^@E$@5FjTbMXYbj)hUMwSZ$N7O6=t*QJj&W)rozT{R$gRznJng1 zlQ|re*JlAagtM-%DyP{Hhl#_8x_e_8375fvot!uS^7p6d6;L6Dg53TLT8#wN!Dd^H zJa=~yl!u1L@VuWl&NneMq47D3HYAhq^V@J;EYre7fLxBWwXy*uv>OEv%d20B7Iv-*b6mSq@>rC9db(s*k=|Agd5akqELs8D)-v+4g64ZOqTY%vNE>><9 zU6gg4hv}v^C~jJPe*x@pE53E|49@IrK>o}RAt5l2=go=xlO8d<&a=V2-|w)Fm>o7O zas{xBxWCeDLSq*9P*&M{vY(byy8;=d@2n=^k(p8hyS)0To4qIdvpH9GQ8atE=YJTx zhj}G?af@Sa^z6X!S&+5!^gC{HXKl5@;eOHI@yYJV!5z_?w!Pzyle`3(#y?HHC1m0+ zPXB%Le}=-*wq=L;xv@_NZO~jgl@34!6xzmFo+wXPAVOj+d%AZ-PGmpjd08N#Bv-pp z6aHqzoqwiJy@*y<5nWJJ>VYLS(hMxQYVht_vF~}jzO2ydViGHbk+?dc{-Q4N_3r+} z|E8l6ViG+DN1exMdpBJwn(7YV>t%Y+gE=HV@6QBUE%BdYvHh~b$+=JYxn*iLRZW_9 z%(5>6kzXUYZTCVU&M&oIG9F=Y!qDSq^+om|rtyl<>No`uS+c=J)~u_WUCv@AJT!$& zsmimyd4-776ZRtrCVTC)?V!|mlZH~3@?jNu>XX?0T;ur&vxlFb9)|$(ar;5_;hYJX zA;6g-8t>KtOG+SGIx-an_bL5>B_^!zf4j9;%&VE1=A zwU!}!QA>G}_<6~IV#i~(_on-%t8u@gvIJn*(Y=`(f4BcV zib3pl7z(ONpsAa+;TPAEf#}x7TugP>^}OrZ0O6;Tzph`Q2*K*8X;ukJEbb|Wcyj+u zpLn3u?(s?AyY_%+~_nXS+e3JbmPfFF1~#dsk{v}b)(?LDfy%!S07N1=!gR^J~Ft$v8Y$E@Q!jywzJrDoRWbUkO;ySWMfGy-k2 z#4ln230Qc)Z^k{kx&2n*DP;UGi)SaX?G761i$3NSW7mD#FMAhi1T$s@v3+7A05VH6*m0 zcn$D(_llT3BoEw{Mv#jQ90Hd871t?6zho9kBKSJy>Q-vx#eYMam($?X4| zw+PE`_Z^h44hOodM=~f~%}~0CaG2ui0wC?oqW0Sn)CF!bQIE%z{~&K(?_(#Zitc`X zSHWTrYgk_Rp8~wD8}f7G_}3#YqYWRZ$z6VN-tsU-_fIf&t>f4HWFjl@0%&X!p!WO# z&F!GZ8B`@TYopNtS`w<$&K(hUDB;=zC*CTp7N)Qn;Ix|j$&J>lp3_kFq8TkikuDHi z*^^!C>)Rltt;Q?A=^BCR zJhYCc(F`PuF?qMCbRbZGr8f^vKLk79R!;_ExQ$YHZ_mH1yB zwQj_zts~>_gPi59V^y3w`TQ{PtgvU`GD2nVc;9wLZM0TMtTI~6D0=Iygn30{6Sb#DiF#{$7W>AwlbPZPJ zBVfFfXomm3cSB;JOnPw~np5_`3~bK5os=k{H5r*6bDh9M4`K_kH@Kgly?%H>QKhCN zKu7L-+9x{~#l$ExzIdah?e(0xh#g%j-dDK9k?EQbHbV`v z?`nLO4kqndmeQ6_!}!cl!WwD+;K9H!u1edPw7m4>djWs^Dx56I<|5$|$r!i79D*+L z3LGOLgBZZ=50lU=Gb6f^hS@mcom#TVm<<@HRK#T>m7ClGCEgr|3)T;k*lccpaQSN( z@OTN55GO1btc#r410dHU*Mt+#P?BAoQcBJ@185(Jv$j=%2`{BQ2$a~=JGG)P(p1b-Y_RYNP&aX?N6UY?E>QKVfk8{J zKafGQW*FV0CWi8owsB4loLIdg)Y%RKBhJ4B?YG<64g0j(NjH@%mq3URS|}?r{#lJh zf(c}&upc|s`6llPC4R|tf;8X?zEpgT)f%%&LERCTX%%L(%t_|Ri0!1Ju@0R5(qv^( zfoDt^nYV{L!LT1->67qLDid5}bppS^SU1%Q-8?W=e&dQZn<-jSocOSkSwZjrLLBLT z@(QQ%Kqd?sCqoxb_K@z%-Cy4}ND`2iDy}sLW)%I@l#w~Noju@DjruXweak+*Sz;CG5TljDsAa!EW`L`RICUDam_R7}OXlcY=yv1`c(?WPZQ1VvT5WWB6 z7q_zD!MBDI=gQV*G!VM3ecz1ptdro0Cx5ChHgqa{KSv|tXur#^yM_uyO48V^3=N%S z+K9H0k1|xDa+e&8$g7=DDM7{Uu=8}x!JoVGec9S zr+U@~uc{q|81alQ^iaxaOZmWdwH*$qTRuPDOq?j9s*TWC@+*WO!D`q6dab)8m5l0usfOm4n@m|vSks~3r&cSggdp86RC}K?c2ZYKsk_zw0P~#2kLQTwhA#nr@0Mi_c3KFl&-91F;{7jeqPa1 zPe#b>Dg^~AdP$lTHP6vv$^5U#xgF8!PP#~a0;Df^_UqWk{-l8 zYS%pc1>3*>5{{Slqc?uF0}kQduVZ|PA5fju@!#T=T3{@##I3BN8dAHzOg5CH8@-CKt!nEDE@#&BLFY(^uHbemY0^a&-LxTX<>V{Hvb-?u=RRI z>nS4k|GMNul3EE*$M>@#%KT_U#H(=l#U<*rVwOcv$sgOS7K_tB9c^OC5@B%k;Kq(F zO69G+`l~yU7pCx|bVM$Fl?g|uZMt9$TK@TckM9_JrMwg}C%DRyKm6-BkWx%WE7FK) zTH7PaUKh6(rJQZa2z^x{rmt=`;M2X6AEgjhL{Vb2>~my03b@AeAKrKt0NpOup^H@o zeJ)@^r^3g3DCbEKt4&hbDD}1zMrAL#<`w?U7XlRl=_hxIV$*7c(wEe9ie6V`3X_y% z^hM5T~dv=QzhB}Kg_50O4S$WaD3G-X2DBb`6R&8a~E*sP)tTIWTvDQ!2H~? z9JO-iBj8bgqMNS<*?+Jejym^i`XzbWai@K(CDL>CND1~)9djaKfVF(8w38_^?I|Cq zO57^x@BXj|Ym_U$s;N)zkH8GIn)(Kl&ABUgMwJXJcW{H~tH2*l(tDm2M2TheIg=MX( z`Cr{af3c2o*;7$iK;BGk~?Gb4DX^$Kg&%A5C(J5Fzn;Lr! z6Gu)0Cq~c)qKJqd)2lb{+|*y>Do;zj@F(K4=w4Cs`O}AEQnoXD z0fDC-WJpW^CFUl^;jxjLz%s4R$15F1l`$fFXWge`P+cPB^-}78E)`@BfHlpWS&3cN zwEYDnwakmCLpcGBCh1NLnlq?++oj#So*VFVJ0%TplhjdUatSghp(WB{*GH_jZOnIC z-3fL|DRf83jH~0>#Y*uyT#FmD47%vZW9Xm;{fhCozf1!y1*PTfYXDBY;*t{^ANFxilN4Dldu0R5yhA?VqTK48i!VPa?nH4p0Cr=?9piXuq4Dv0VW*&PfI#<~UGUDKrJ-;`57_cOcCn##`)dp>)VCzCd^d+h+4k*>@R)C+ z>L7JT%?snaFgdxM8OIZtwVB5vi|798gzvkFLvH{fP4v8n5*c~k(tLk!9e^acR!`%~ z5r}yFppf0~uKrrFe*)6J38#!0y!wo<}2 zfzaYiItTW z5nIioeXv$>d6uDHdh(Rrct!0>tZR50Ot`s3ITT6Z|8MQ^iwTcru(~4IbqPQxj~kaH zfBq7H08;qz%IRW^Z)X_Q)-!J~vCLQa6LriiP~LNd5Is`}F-VlbMKPax6zBJ$yjFmJ ze6tgf+`+peh;<6>))&=&d8Jg#Pu7~h|3MGW!=3FUfxHOBIGlVE(A11%vQl`zyQzF7 zs5sE@1=76*_vBe7V<)izJr`&DHL|)s-%%Kf{BD-`0FZW{vlGsh`AUC^z;8{oaH)ho z4y0|NTmzT+9{IpAo?Vl+_riRjS>khd8ZIV`vAkPXLp850Vrqp^asRlAEcUZ0F=P~t%TVzc_-)-lB%PB{az$H!KH2>oBzLJ#$wn^=;ftuLRbK7|ptsNYpa+Q_0N zcLup>d%4n4`xaOshijGckU~5}nt!A#{|3uUh3QTCdo2_ME1EKexrCLuT0W^_7~ZO( zI(#Vpt7B6IE|A*bgJzFP9=90{t+6xibVGkH9ncvXJjE#ay9p2%ojm{knM_Xt-MG;q zx1}re9JKpgWTef(&008dwG8~uaO6&fls7MXACQHZ8Zsqe_P*pK=gETZ>X^TmLS+#p zO!~^xb;~e?LXGbh^H9-Nh|RWDX>MBU18kh%Pgv~UIz@%wyU>leyxZhtOxksgQ+RDA0u*8RACCvQ_BEihUO&7%g^QV?pmv~oE#DU~*KLw6TU`3o zT&56pKHWXR1 z)b-;CMClwRI>IC={oaKF2-iE4w6uuqIuj_MQU*x9WfIyGdTF<3$#Vd7FPm}K9RjVS z;7?KHpF%KriDHqYm`zs7K9Ir3yC3Wgz4&Qr0efK%@t|i*)kv@OV;R3erI@kr42L*GZ;ECr( zpCe1tVcz`dBh+*3i)gg=&6fCTj5qDh_kX~V?%%yY=Y>e?y+7Ktd7b4^@4NYb&{vD?Jca#BNkgBEJ? zCC{caoN3En$Pm-{H#ljWe>*~BPS1a*^ep4G+|y?UVE|9AmoP!Dr2zCdN2?hS)1ptJ z7nxR|FFDS32FLA-)aaq1OX!-9wtBWBYK>jgTZ-Hx@!uXIV4$h7Kj06rAqf& zh*yJPB$BUMj%?f*w6lTCbYsPE)^U|KLPfNR#C#v~SQ%nLi7dl3DUP7TwA5#6-ZJKH z)`BV#)B}Khy*kq{cNrfD7M@j7{oF*Sz2fxom)%Q;JXVC#LPAl6Yx4x1ggo~G1%`OE z4FUXEGnt?AGP{DS`VDAM+@ahpbW};?YI<(vAE%u}pkhc|a;fX2EW;MY>a>ED&cWZP z^3SEzOQ?dJFOXv~k!h{x%Ox<#&Xmvxrz9%$kakrvVKCwSQz84BK!s`i zNgZ7TEzf`{TNhqYn@(nd+r`ZT>Nf?&hRi*6b1a}oNnZ005Y=Qlq7Qx70!i^S3Zj-g z0#Jj6d3vjLgq*rUTBB@*8(YX3AQ)mQcP+GD}Z}eKQYuS4L&Px-=UgZWv{$4M4*c$LOaF!B8 z(B=Y3nqK4{s(FG^Zl&Y3mFj|`T%jiP*mKVo#T?cLyUaL=mi`Zlt@wIrj?^PDlnyaW z>sLbBH-O@g?9U2BEbaOaUkj$HlhMOzNx}x9wTRd=*W&7-08Hs&qiig+ z>wj*7H=P5jqn#(+c5szc)?1-^RfB-XD=Q#CD?_^}+`nHFz61rwNKFXDO@ocDB!`vs zz68TpdPe!WalwO4n?Q}aDZIVy^=S6E%TTs<;og!^?U>KV6rM)QE;3`8n%=-=lV@tV z4H_i>b>;OzM%J$tQp(LGQ_*~zH(%p_RjIfB&Jb-sJLZxVD+N0Y$l4xhxxAt8UMxQ> z-*oc{8CreI1DRn`U)g7VYI4-zy8dweTau-klo2!8@DKqr(+zSgB{Ca`&TsV5=^y&y z`?=)@6KZ=PgyvP>Jb^ zTij=R92e<$v>!Gfz%6G{O)n(X(c(!X0;R|oK$;Zj`ZvI?1iH!VMIw?t9$osZk-O9p z<@z6bEIdQn7Z^U&Ae?HOL98xo8b341erP@Yjy5HMOrAoBg|q>5R*_2W<|mA7eUVvs z+oyQxL+&K{8CFJGoD9Bq{&+NnN8tcLpR^&gF0ZXC3}7j#Fj z#~3>W&PJX+?}$BnY1Ul2z4@`?08@VW8P>5(<>?tJYJRhbJ92@uRUKjb6-sEp4?kev zag-*MY>969&2vO9!QM7@K~7F4!ECzOoM)4Qb++ALFIWIrLu`?MD%iG?F>Z;^)EM{R zt`6CUm|dVbIXae)B5B1$yW&n~g1BNdf45@zbe@i)#RvaY;yu19i+pPL-(HT$G_Ll& z3%J{9A#KoSNsj$9Eo*FvN#cO{GpHVNDv1C4i$$U%dCU*EXAooGinbLGlU^E4CBkbN zc$qIJCf!8FA_ktSznE|MN^IMS6}o$a-jl=)3_=W_WG%Aonuk~Wjfi+2`Nc&D78$35 zE>S;{0bS7n=RF(!&dT$X2j1U`y*py|xl}dM5 zLHYc1q0!OD#k{`5(Z$77C<@Fl_pV#yI|XrqKg}NE$r1X8p?? z4Qu#hTXiGTLqzduCMgMP9Jg|-pbH`+?s#}w@@CPO18@SdG`iOah!8W(GF%0Wq(96= z@?6EP2oips==I)nCiG~=@j-ZGmRo_;y3JRq%mYSxT>T+x&-w7&s`W3WU)hJnDW1^J zy%1|z6Lxr~;#fe48Noqtjg7~fje_~2SIs$a^Q&HXE~-Idrg*6XN3FiKg%E+6r+rucwQ6M&`Vk$;z}_x;8z~D`CP0f3Xb`ydgS** zbJ&BbC*2-cN#gholG6K?rzp1h6Pir!$FAzARd z8{gD$9BbNoeRJO9;SC&A=_ga(@#o*p7bny9@8Pi-@s=liglMUJ0;o3f_PJ9{^Sri) zy@Exzd;}V6$VO~d!`*7RDJt+sK<07rZyBf>5OFZyzJ|3qTv(*xw10wUZw^ zQ2Dn(^?I;6z~y9(b0^n&tbV`{5IW-0KALuCpWnOryTYOSDMdK|{;%`TY^HEk+^yFq zn~!A6Eo57d2ZFEs^97M<|1d3BE58v@!jgMOs- zwJBl-O!j$zS2Em-{l%1mKTJgG62mvNFL2vXX=i$ZVk2(gs5Gdo5Y?!(Vd@^LVxg_` zJRc1MPq7pI!Mcg_)F^7SF#IH;hWUJFIFPo$hbmcr;y%8ogf8fJN|rw^z@l9&n-bRD&62jhuFU zKpT)g&crO~mReR#kQa$64!`;LUG@kQT;r(Rx|)|Noh-f{R>e*)XaMCz7cjCtLv3#G zN^WniJyLrHXB0}Q_tfd~_I<0yL-tojw%}ymZ=Kf3xQT?sqRDb!u5P92vJoP2y()Q2 z&qH2IcKO{I`>G;*Sf^h&A2YelJ7ZTP3}5^;wIi%Rd$H_FJ8I+o%6$`@cImU7U=4ME z4MS7#H;-R-dgfykg8E{&NQOkq zYb#KoG{EhVsHZdqQ}o{|f@7fXZzBOC!awZ(XVKcR_32rmb#c~xQm-7uO=+${ma8em zC_Xkm^ASN-f6;G~&xC-ZW=DvlJ^{N=pU{jb4+cAe;=WVynF+ssuJ+{b2UbYg*eH=g zdtLAZ--@r>P0UJZFKnQFvJjF)$D5BLChU6_=o-l~u$9oh`xsk9gZH+0Vy~T66|XvO z-fS>Nu7aNdV(%PXYg;hV5G*gLl$kr@3__dvkvu;5*3b!lLOjq0VnOb{ZmQY(dg4yT znB=*HYtvT}A#ZO#L$!r~kp_QgqSq?E4FsQWZj6}CZ#G;!lw!=&^?6T*$$36vLMpOE z5(iE5-wdt`Rv>0WfgoWP)TRe#yWcujx)MsD=dt9b9ZS82@MfczI+`U3+9D$>c?lgm zWFVd&OGX@71G<^>$bW+|7J`-#TjSoFr_To+X{BnSK})c!zQD7psAcGP zm2$$TW-or%{d9MLJIrBOONQO1yiupd!YHkHB4~}kYs;(ok+?b+hvtBSpoedxH%-?* zGZ}?=%L_In%Sk*gjw2S5R!ZDc;+@t%3N<|VC=4u2f1s&N%yzlmO8;cKr68kKW;$OG z(6ZASX<9l?&pcSLz>Rs6o^5I?S8n_olSCL9>hUhlb)RQs;A~ie4(9ylB~3;2hY?H% z@+sdhX%fM?=JRLd85bB1(ua|x&lQFfHU2pg!A0lE-vxN~%U(icw1K%4*ExtXa|*0` zFEHWc7H0wDGiR>bU+oY-2v1uFmCQh~I(7u7V2+Z$aVWm?@-hIMd6-iBh4Ik8DT7)&ZA@~B7<)RE|jf#c~yd7qzPCGwPIly zOsmc~lAtl*4m$hKSnbVK7h?9`)`~N}?C%Wx${n&V(3{Z>g@lt-igI4lD`x={Du(5> z1H4@pB{?@?e4Vd`R)DQj#|p?)m3~K3MuqO7s<w;-zSG<;6}{H|29OoR zzgO)0;%MI^^6ry-cqyZ3iz{@}>Eb<8X@Fm6@jOcoP>XhRq8$L`b1Hh$vAt4)0v3FX zk6Jgq`zO|!{u%yw?S@k1n)5Jx6+>}5HE7ryMp;9KNSZp_^OzGzt(I|=PUC!^l11U$Ek z#;mA~ys=e}IpBlT&dG#`qh_AvaDJDb-a;L< zXqGb|zS;n1sjr@&n6Gwb4n(EOj%i)|Qt~e{Q&Nuh^=m~Qd`t?Ea$u;;3Ra9C!$@%dav~s?#}KNZ@?!SB9;zC3J4EKz&KXAOCrvOhpAO^&pcxb#zWc@;V4|QIHlKn#!L$h(IJ#-DtR}Uywztz%nzLbM zy;C_TiBgql^~X}auLOow4UW9@k(!BH^9@FfDq3`?T_aYfl>U`WGUN=es1yBVpiZvH z(N7AlK0H;pO0(Xxb{H1U^tm5bIcH0ho^?X$;95j|AIklQ4C`<;WT|OUeo!MS{05}q z_E-Gdc{xN$)%ZJOQ$gTvv1!&I8>&D;t6s7!}11PqgCot_rNWXtrerh ztgN=I%{c9jZ~6m`2yA2WD8dmR#1^>l$TbSL(hWryxS=xiVeVVRf(N_4&3{y9AJsLK zR&6=AZH;w*`b|eO85y4yD-n_=9QpEF2j)95z)|kaDi7}~^*MLKe zNu{8(pW2)(2-y=>E6Bk>Ryk|FUC=8s$woH+LW`2D8JPBijHy44PCTVZL%;E$ZT=Sh zx`MSCLOs!-X;rzD3PL(M>UNg_l2M!MDxF(^lc9Lt`jgPWb1m{Qp(~=Eu!zEoBLV+6 z)mM9s7T(t|+4#k-cs*Z3#Y$Ca*4lSfDRYfCqFO^#- zXiO}o#0mzf@zK`g2G=(5-Ead}c{c5G7Utz!`gGnWW5V|{YX*n6S(w0b^Ez9u4_ZmGemT#HA z(mVpy1xW3RDekpd#QjAW*EC2!Dy&V5ne2P~BTMrJs&@UVOu$YMNwR!Q^k(&i+Lrui zR7X%6&GkkW9r)s!QgzH;@xN=g0f4g&3i9^Jytv9{_|7i$Zl~ z4K3>9)-C{{)6`@viWt{vEB!KmnlP3zSJ`_uzna9w;T+k39h23F$a-JI%P&02eJ^3F z)*D7{QbIIPI>P7o4$h)-m+(VmH0#^09QteiBzQ(L#pZvI=p4Z?Xtz~a262#qHJH4g z$UMGI1C?4MnOY}yd>htHjwI3PTN)MzSF^0dwgRUtOr`&^gp^RC>PGVZM`->-?Et2n z&GbFOKjc-b!t6)397lOHCW#f?bNxtR0~AwApUr<3e=_yQw-rV^h3$PS=d5`HVRI)I zbd?ok4z$|Zc)6>^>Df$j1bbdJxa)rw(7se!_Tw?8p}azf9xt*rP6n@7)rg@+ne$(J z{s7uXb-vk+CKHuwQJ7MQe~!%$nT=W&`$0+uObyC^jq*{nU-;(ii;o{GdXgU?!GRTB z#|I!ZK3XZBQg_cRH4dNHGSjP7ViZj^p?CILaV@+^jo6VDl2^&O-{T1T)Pe6wpZk~L zrqG5~NauY;|Ifi|HBCm1d;R!8bfomC^T!nH#r(4beW-OT=Ob+PsVjZH=^51|5V-IM zbTtZDR1`-lYuDz6r-^Jo#WVU9^;dIBW7Lc@Q?L#inx@AIrC2TyBf=~t%BmAcx-PNkHpN{(-9%(gR1Vw2IAH%Y>T>V z*Yi8|r8t(&eku4m*RqpCor2FrGuA-#9IJ$*wz|!g(~z84e_7BlRT$mZI&X0D>U+DP znVZRJ(ZWS9;*3i{(e!R9{l3y8`ST6>wGf&T-=nzV`d@plHsZ!PcNjEXWg8sEj)=2k zDmxFgwAn7${5s*x$1+CB`CJCHK)(orKSg*pG_|lia8Y+{#yYTZ706}B1JSM$9(J+Y zEVK2638*mA_(Z$4l4{MRU#;;8i*2fiidbp=C92VezrPt!EdK$C5zhYfwN;HJNdifr@bg#-@th^bwfr! zT6A^8BHCJc#f|32{wL)vtc>Va0eK?Np5;{a0sNC?y5+BiH+j`Jby2#XA(K(LcJ19Z z$v0fh#Bt=b=Qx#9oAdVLU#{m~e2L_ldtp0Wft@}{BCw!XSTfZ{w_Bml<0Q76>@*=^ z_$d&rVh5&nZEa2N*!-+4;Jat;E87qeRg(C|aEX@}5{5Ic_mM^$`Y2QC&oq5i_^wOr z|IzaX`$etkuqmjBAj<@+8%IVd>P=sHkezUQZbKe)-tpf(YW9W&WxQ&SBa!9pS7S2~ zkmk<)_-_EO)=-fkPE>=UZZ_fzm7=>GRqnn^$q}?*mguMKB$?5N?!tWTw({0^h@Rq z++{XOvU#En@=ARef*o=5E#4I+f8SJGu+>~^)RTb`vizL&= z2vzHm>D@R)Eb-7&l^H<-{=bJ)Q{R@VPL+&69l+MTx-HBsiSo##w>UWgmy-D{2 z9n|^q{GMQ;J>_Lr;dqXepblRc(laBv=&mU>(xBLWcI$V^v1MTwQB(JfhY~olRYYH; z-W=F`_$EwU!OFBn{NMGjNEG38!PTUw2U=5fmZxMYavPxQ=vqBNW;7ME@*TVEgRQ8Tgs}vY4feMaNC274OH0SPmxMRe91E{%n|R3t_EM8D|zWd%&|)T{?KGZV{7n= z0e{rOdwkfjot;kmnpW=0Hfu8ny;8sMiHz|LSMIxdVgqGZQk{79L?}szI)7*9@sY;e zad|v3UssRsN)g7*vy9!cN`{coCB6ZkzFJvI#?Hg8zkB6PMrxYcy5^TQ@6Ok1jeYaK z#?XM0a8Hk7zj0skXxBFXqxsgDR#Tw*YE{Ed1mRm+VSZEe{k=t@51-My1FQN>6IO^g zOEH1DFCU65g?@94^62#2GzSyrL{%muUmYI!>Mh`f)z9jf&qCABZl|8W;qBXYt}md#kDU6w@0}VZovhx5QSUW6)oy^s zaRu`Do7kY>#lck+#$49HYH#!NX;2J ze=8*{sb|#qI6jC9ARnF;B2?BFD%M+tq%%5Dm0|nODfXK2l`FV6Wst#q2}FXiLPRlI z&Egu?(~SdWs;bB1fH!sITMqeKUR#0_upCbgxsVy^+o}#G{+9W)egBV3hp{u52^9sJ z;u9T&;+HJ~@nSGdr|2;E;}@g%D8gI(s=Td0B^ty4=u=DDqLl0f1=EURC=aB>Y3q07 z%sbAl{SSi8uJ(Hm=i1~%Oo!YAX_)qpEWh?I=k{9ar;N2ZD{^O#Pwaadhzqy~*6k`t zr<6lirXF>K3{<`lO(Wh6k24Is_O9th+tW*NN_0HTvBD9UEtN$qP-uLsp~6WJtK3nI zO2y*is7055-l9CKI=9$yMYe)pz@0ZLs)863GplOd5cr-rez2pbsnl2QZR)$74lZRm zpV880Qmtx+fm@!N&hQn46YuB!hYC0|w}%v`c&&fo9=vLJ)qf&Mf?{W8!ak}fG&jKQ z8mMn@uB6dl8eljeVw+S9HU-PhDSV@{d?_)?VBwia9Y=6Bjg}_y;ptjohrsMFTWAQX zHQ}H7sP%dE?ja-iUJr9On@5%#_qeJzGG0gh6Vy?f?U;bj7A+#Wpcddh4E%OVZNt16sxySbHv)L`e_ z^Q%_y^K^f19hOs?QM{&NKuJSV*Wzt`38_6b?OfL`PV#o6zPGF2Kbj#&b%SI2S`t}# z!BJH~*{lQ^rgv=9dYN9i<962}`0+s>yUPum@1<5#7cl)^bRfco3_hOmTRLOvfi|O; zMB_o|u#p4;%a&!kzRGE<5T=Z;#$jykH#UZ0UM)YGhU!_QJSEN9dtPXrkPFnLqPP_&&0~-{8A*zi&L{p2rwAL66jW95#F@s7p@z zip0Ip=tbI35|B$&Zh~T!#aEzvt}qXL$}~GU5UZdu6Za1q>{Ut+=YaRGEJ5^zGilci zs{Z=*s*6`u%;OvF?Zjn-wuncZjbY|1>P0tHDod@kL4S*23i=Lv6i96C8+-yejKVD;m~!&7L=dLxoz{6BEB(X$$0+?{UC%gKhNmq zFH}X-dR?}lQU`_}$T1MCmSQ>`)^p^24h@+xU|KhrW!l)41FhT$#3IE)G?4x&W`kWpkSPAwIBQ9mC0kmJIvwxI%JGI z`1PJ5LnP+h{|CwP-75ewFzHV3$Zd&f~-P5wTCF$q^yZz)fffGuIAjNbm#b)O9T zCxi7fa1T~@X#?4_mF|z~>((g052nRwHGTp?pF+{nokYvHkyH5jLF?P)@)YXau+x_a z*#R(hhAIn!4{!i|^hnBrsr<)*5NLF8(hQM%=&|urg63zGy;{D^8k|b04jkRTr5JeO zlIvt4prF{WTcYzKiTZsM2nRN5@eJ6F+Mh>Ye%N_m1cPKWgG$}LT=Y#mIres2WZTxu zvJL1+$M#7*q6G=XNPzE#sX?_$@*IID0$*WW{&NZUO?H*{K}bIuYv4 zKksE2N(b|QN;wmMD7&za8~dJp8Pt%i$zH@z53*++Gh}V-jFBx{B)hTIFh-UVLyS@O z>}$40vXp%dp{$P{p-}HV@8|sw-hben&pG#f&UIbq_x)W$BRp-^npk!V}D4p4j|;CsA+o@{`6aJ&XPp#>6ewMmp2TB})!N0@a@X z0MN|-*FDx<<|3oKr1HbQxlEURn7BU6PjG+3Ba@sM^Ywe!robte;tZAd+s%Kc7hboM zDjwWLFtRvu$imETl_{d?0Wx(&BKCACRMqiNV124}V$PFWCXmqg-DXtSt%^NjgB@i8 zZtw_HET#pJFee+SSTlUwSw>INZ;&6d<|Qk?Qn4BpLw(vpAWq7i$A3z0$uwq{RzX}u zz7vUQ23~WLW1C%MtZoVgIe>^O>%8T84N_8uHTJW7R>BNvrId7~a7Mi;a zjTMU8gY9%$i(J;&7S{Is;a3BwUJgUY=jd}6_7xW^b+PzL$*x4b-V^Dw*(v43dYZ7(H9I>22y!tGsBfr{ z6%F&!;8Vb9+oG19*g-IY(>&Q^(&k&OYOFl)&f7YH1djoO@*TIf4LQpVKRovs~O zH9?C-8^YSx#DpQ(6T;UkOJHoS(X?sGtaXtvwr?|%VfMzUlWceX zL0pP(s+wMw4!Am_^v_*-4J5hmrt{Vvq~Ny^%nvmyqL~r&&Kjo^VyqTo_c2H6J zs+qB{O;*#U<@^>&c}A}DWYvyG>7ZOUy;r-KHD3hP$! z7fcY2P9t0I0Sz8V%3I@wY zLLZvzhH%ewH~wo_b~Px^Y6TY_ zi7dz{=Qn<3I)!F44I-zI!i9ffl=R_WC{Uh=pJ2CM;`KaDF;w=6inf86u7_2r^jm4o z)Cl}1*OjYm=%0DW0(dRK{%}ZQCcP5>Qh%M7DajBJq-A<0;2^X`62?~ zpt$taC_-|5FjsG&T)8jWCmovOX=?o_T{-La6=hmkxzqs>F4~|0CcoI^;cG@_KM3C9 z5@fcO40&7ii@%Yd=N2>ohl$GQDcOK~oF=BgA~CfTF73PBLC&IUkRiLAxnqYRjyuYF zA8oiBjV|_~Q1RnC<~DT8->*BroZ2=G2nA>1M#)33>POYr(nVRd6C}&bk8XARFo|5i zXWL{LZvBkDwgRhcf;2mK4-jQsZHvH$*nIWhIqq_Z5-th@vz=1LB@`s0eg96qRD<%k#81*kgfi(7B$*evs=l zJ2L+>Tyu+53zpg~>~JHadT|bj)KHi8$(SqTG|v5m_dzZ~4`X#EU+gU{6lHD1BytA6 zlqmdh-|D3iA|_d$wWw|u!I2>4887~XO1(7_$m*(iTvJ z67H-U#!OWovX18LzekN^!hysw>BGmgLs~UhnbWK`u{@kV-ET2$1BkC5y;-7+WL|K! zV7r}L!;9LRb#$(KsMBBMD&&5G)*aQ?GIPx6_uvfQ0FqvWM24~EgDoQ7Rv1c~ZG;{J z8PXXgn-gfNV+}5p3EoI?$=$kE-utuk^Hg`^{pGZd1hA(l4ktPx)&k#%DM@i?pWi%s zc#CC8)JIUnW{<*0gPqS(EAULcNfYNI zn6o5b{oFqWf6|PoNQxhh+kf?_{|=z+Xj%Rv+-kz1gy3}khxda4S}xp{ipSslst zgZdY^%%Y(ePw_>a(Y(rq?lRGa&&_XGy*R)BL49$Q2w95%3;_zP7^WSvL|L8~HI!Hy zzy8uevI@z-E_b+NBoYtPl-0Du!)5{T z;pg*7CoXH2)`BW_(Zu7`D{DG#O)ky%H?zbNL!a1-%*>JspVMo-1jvh+>tMLLj48h3 zBT!eL6K7=TtIgi_^`Y)Pez@TDLncIfLs{?^iwq!qJN7QLs&p~vF#_DqCvTxOkQs~D z_rpE|;60L(+A|M_Pcxl@ubu8;Zew({99?e^xuWV1AbhccNrxZvs7Q{|K)ny}5d43@ z$eV_&&V2ftlQ*wN?+=4Oc8)na?&*bZJQ(60?`mk5ZuYOy$|N!Yb7@(M8p0Lx5vtzw zYQ)RM&vraoE>TgPXKj!xg$f!f9oZOB44dJ9dvzTij+LfGNmc;sRK%KqGIX}{5ek`L z#*~VTQG}q0+SJjIHQa+^_WS`g7MGUW{?n}urtqTc#CA?Pzk4@0GQy1E*&UKoRE~zm z;1eNAEF~M5irO#cOp3$AzrquJ9NpAh$IGP0k;YVFqFRypnHfW$!(uFucSTDBpkHLw zL^L#t4MGNe4MGN1n8&|8@$Y!ff$57sFrt`L0~KzG0k&0zhrW`bVEg{XuHyj^V}!wt zSf3&0u{0{5lW@brc}Ae%z!&NT5_ua&e^e1oMHLJN8qLZ0iddHHXGd6-Qko+ z>1jko?T_Rtm|hm>?>QDP;6N#+P(my)^lIn?ESev7Pvr%*;y)e%ao0e}cCRKsrxbN= zwDWmgo^u*82ezqOMCyoB0Z8=nb}9ft(7$Aj~zs~6RN;;+PE1#PuGu;2}CBpVLSoQPcCg1pg$ou*sp?n1w&;y{i0myp1 zD|IL=B&V+Xzw)t2Dl{_tBC9I9%N_6u%Q5lMSlh%oSY5}oq0i&}dQO%W(RW_^+b%zh zT1H=Y;PiHn{P4SK%Cj&F+`nZ?h;x@Lh|ca5H9N{MsGQI#gH<$?MOz}ae3ulr+$*0O z@$cH+{I+3X(W2h+5C%2<{UCck3JMwgvcIn*s z@x#*FPCG$ZQ-$Qa^+CC)NxJUr+rItA$fs~`vyp->raR zuZw@=i=G4u1T;^1*~QZ6fG$=RFSE(=cSB!>TQb1@I@q!0A|5MN7Dp1i2%ykEzcz1> zaV_Z97C5UA2n)Dt6%Lua1bos`a2m}z^ign zxr`L74n00l*tlm!u}5C}E8*Dk~p`Fx04w-HULH8l@{K{-c0z zH)0BXeJC+$yuUAj%w~zLm_s=T(G@GTlmD@uw~zM1{WRCtI=YVxZ28?4x=lmz@_1T7 zo`6UDpO5_Qi`Xai4x#6MH-#zed(eQ!EFHGRt6Pzlvl_P-ztz38`elA^Yx~FJkY^cF z`>^velCW_X^4*)I66i13g%cKaOxTF~@s&v?2V`9x^KS$vKgp)cxBMMQVXcwIsO_A* zrLlM_{1$aP3jSeWu-JVm)fLu1oAK6W>MWeWWP63^D z0HQvo2zZ(f)9`^Wsr||>1F*Jh%>Scz?4L`*6ZDV1t^|Jon&r|M>znIU>7wHP2OSM< Ay8r+H literal 0 HcmV?d00001 diff --git a/docs/en/proxy/deploy_guide.md b/docs/en/proxy/deploy_guide.md index 6447d5b6b0..84e5a3c171 100644 --- a/docs/en/proxy/deploy_guide.md +++ b/docs/en/proxy/deploy_guide.md @@ -1,32 +1,37 @@ # RocketMQ Proxy Deployment Guide ## Overview -RocketMQ Proxy supports two deployment modes, `Local` mode and `Cluster` mode. -With `Local` mode, `Proxy` deployed with `Broker` in the same process with inter-process communication. - -While `Cluster` mode, `Proxy` is a single cluster who communicate `Broker` with remote procedure call. In this way, `Proxy` acts as a stateless computing components while `Broker` is a stateful components with local storage. This form of deployment makes RocketMQ an architecture of separation of computing and storage. +RocketMQ Proxy supports two deployment modes, `Local` mode and `Cluster` mode. ## Configuration -The configuration applies to both the `Cluster` mode and `Local` mode, whose default path is distribution/conf/rmq-proxy.json directory. + +The configuration applies to both the `Cluster` mode and `Local` mode, whose default path is +distribution/conf/rmq-proxy.json directory. ## `Cluster` mode + * Set configuration field `nameSrvAddr`. * Set configuration field `proxyMode` to `cluster` (case insensitive). - Run the command below. + ```shell nohup sh mqproxy & ``` + The command will only run `Proxy` itself. It requires `Namesrv` and `Broker` components running. ## `Local` mode + * Set configuration field `nameSrvAddr`. * Set configuration field `proxyMode` to `local` (case insensitive). Run the command below. + ```shell nohup sh mqproxy & ``` -The command will not only run `Proxy`, but also run `Broker`. It requires `Namesrv` only and there's no need for extra `Broker`. \ No newline at end of file + +The command will not only run `Proxy`, but also run `Broker`. It requires `Namesrv` only and there's no need for +extra `Broker`. \ No newline at end of file diff --git a/proxy/README.md b/proxy/README.md new file mode 100644 index 0000000000..2a704f7a8a --- /dev/null +++ b/proxy/README.md @@ -0,0 +1,59 @@ +rocketmq-proxy +-------- + +## Introduction + +`RocketMQ Proxy` is a stateless component that makes full use of the newly introduced `pop` consumption mechanism to +achieve stateless consumption behavior. `gRPC` protocol is supported now and all the message types including `normal` +, `fifo`, `transaction` and `delay` are supported via `pop`. `Proxy` will translate incoming traffic into +customized `Remoting` protocol to access `Broker` or `Namesrv`. + +`Proxy` also handles SSL, authorization/authentication and logging/tracing/metrics and is in charge of connection +management and traffic governance. + +### Multi-language support. + +`gRPC` combined with `Protocol Buffer` makes it easy to implement clients with both `java` and other programming +languages. See [rocketmq-clients](https://github.com/apache/rocketmq-clients) for more information. + +### Multi-protocol support. + +With `Proxy` as a traffic interface, it's convenient to implement multiple protocols upon proxy. `gRPC` protocol is +implemented first and the customized `Remoting` protocol will be implemented later. HTTP/1.1 will also be taken into +consideration. + +## Architecture + +`RocketMQ Proxy` has two deployment modes: `Cluster` mode and `Local` mode. With both modes, `Pop` mode is natively supported +in `Proxy`. + +### `Cluster` mode + +While in `Cluster` mode, `Proxy` is an independent cluster that communicates with `Broker` with remote procedure call. In +this scenario, `Proxy` acts as a stateless computing component while `Broker` is a stateful component with local +storage. This form of deployment introduces the architecture of separation of computing and storage for RocketMQ. + +Due to the separation of computing and storage, `RocketMQ Proxy` can be scaled out indefinitely in `Cluster` mode to +handle traffic peak while `Broker` can focus on storage engine and high availability. + +![](../docs/en/images/rocketmq_proxy_cluster_mode.png) + +### `Local` mode + +`Proxy` in `Local` mode has more similarity with `RocketMQ` 4.x version, which is easily deployed or upgraded for +current RocketMQ users. With `Local` mode, `Proxy` deployed with `Broker` in the same process with inter-process +communication so the network overhead is reduced compared to `Cluster` mode. + +![](../docs/en/images/rocketmq_proxy_local_mode.png) + +## Deploy guide + +See [Proxy Deployment](../docs/en/proxy/deploy_guide.md) + +## Related + +* [rocketmq-apis](https://github.com/apache/rocketmq-apis): Common communication protocol between server and client. +* [rocketmq-clients](https://github.com/apache/rocketmq-clients): Collection of Polyglot Clients for Apache RocketMQ. +* [RIP-37: New and Unified APIs](https://shimo.im/docs/m5kv92OeRRU8olqX): RocketMQ proposal of new and unified APIs + crossing different languages. +* [RIP-39: Support gRPC protocol](https://shimo.im/docs/gXqmeEPYgdUw5bqo): RocketMQ proposal of gRPC protocol support. \ No newline at end of file From d2b02ae8c0e5f73ac03801aeaa94d0cc6ab9ccce Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 21 Jun 2022 16:01:11 +0800 Subject: [PATCH 268/338] [ISSUE #3949] change some parameters to protected --- .../proxy/grpc/v2/DefaultGrpcMessingActivity.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 4dac2a0031..5cc6be5951 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -60,6 +60,9 @@ import org.apache.rocketmq.proxy.processor.ReceiptHandleProcessor; public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown implements GrpcMessingActivity { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected GrpcClientSettingsManager grpcClientSettingsManager; + protected GrpcChannelManager grpcChannelManager; + protected ReceiptHandleProcessor receiptHandleProcessor; protected ReceiveMessageActivity receiveMessageActivity; protected AckMessageActivity ackMessageActivity; protected ChangeInvisibleDurationActivity changeInvisibleDurationActivity; @@ -70,9 +73,9 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme protected ClientActivity clientActivity; protected DefaultGrpcMessingActivity(MessagingProcessor messagingProcessor) { - GrpcClientSettingsManager grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); - GrpcChannelManager grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyRelayService()); - ReceiptHandleProcessor receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); + this.grpcClientSettingsManager = new GrpcClientSettingsManager(messagingProcessor); + this.grpcChannelManager = new GrpcChannelManager(messagingProcessor.getProxyRelayService()); + this.receiptHandleProcessor = new ReceiptHandleProcessor(messagingProcessor); this.receiveMessageActivity = new ReceiveMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); this.ackMessageActivity = new AckMessageActivity(messagingProcessor, receiptHandleProcessor, grpcClientSettingsManager, grpcChannelManager); From ffa5a2d61592bfab135ad53ece930f0d3273c90c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 21 Jun 2022 16:35:28 +0800 Subject: [PATCH 269/338] [ISSUE #3949] return port as grpc serverPort --- .../apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java | 4 +++- .../rocketmq/proxy/grpc/v2/route/RouteActivityTest.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index 74ef3ac02a..63f69b8e05 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -39,6 +39,7 @@ import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.route.QueueData; 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; @@ -164,11 +165,12 @@ public class RouteActivity extends AbstractMessingActivity { } protected List convertToAddressList(Endpoints endpoints) { + int port = ConfigurationManager.getProxyConfig().getGrpcServerPort(); List addressList = new ArrayList<>(); for (Address address : endpoints.getAddressesList()) { addressList.add(new org.apache.rocketmq.proxy.common.Address( org.apache.rocketmq.proxy.common.Address.AddressScheme.valueOf(endpoints.getScheme().name()), - HostAndPort.fromParts(address.getHost(), address.getPort())) + HostAndPort.fromParts(address.getHost(), port)) ); } return addressList; diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index 8d10efb135..ad95e0ed10 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -36,6 +36,7 @@ import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.common.constant.PermName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.QueueData; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.junit.Before; @@ -82,6 +83,7 @@ public class RouteActivityTest extends BaseActivityTest { @Test public void testQueryRoute() throws Throwable { + ConfigurationManager.getProxyConfig().setGrpcServerPort(8080); ArgumentCaptor> addressListCaptor = ArgumentCaptor.forClass(List.class); when(this.messagingProcessor.getTopicRouteDataForProxy(any(), addressListCaptor.capture(), anyString())) .thenReturn(createProxyTopicRouteData(2, 2, 6)); @@ -94,7 +96,6 @@ public class RouteActivityTest extends BaseActivityTest { .build() ).get(); - assertEquals(addressArrayList, addressListCaptor.getValue()); assertEquals(Code.OK, response.getStatus().getCode()); assertEquals(4, response.getMessageQueuesCount()); for (MessageQueue messageQueue : response.getMessageQueuesList()) { From 8e70dc2ced3743e343e20c317892e747555263f2 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 21 Jun 2022 19:26:13 +0800 Subject: [PATCH 270/338] [ISSUE #3949] Add exclude README --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index f8de8d13cc..c67db15f10 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,7 @@ .gitignore .travis.yml + README.md CONTRIBUTING.md bin/README.md .github/** From af033c9aa2390c8b2535de12caf16e1d18cc52b0 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 22 Jun 2022 10:27:35 +0800 Subject: [PATCH 271/338] [ISSUE #3949] Fix unit test --- .../apache/rocketmq/proxy/config/MetricCollectorModeTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java index 2fc52c6e66..59aa49fe83 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/MetricCollectorModeTest.java @@ -27,7 +27,6 @@ public class MetricCollectorModeTest { Assert.assertEquals(MetricCollectorMode.OFF, MetricCollectorMode.getEnumByOrdinal(0)); Assert.assertEquals(MetricCollectorMode.ON, MetricCollectorMode.getEnumByOrdinal(1)); Assert.assertEquals(MetricCollectorMode.PROXY, MetricCollectorMode.getEnumByOrdinal(2)); - Assert.assertEquals(MetricCollectorMode.OFF, MetricCollectorMode.getEnumByOrdinal(2)); } } \ No newline at end of file From 39750ec2334834255c3c25c22524506835437348 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 22 Jun 2022 11:49:42 +0800 Subject: [PATCH 272/338] try to fix StaticTopicIT --- .../org/apache/rocketmq/test/statictopic/StaticTopicIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java b/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java index 1ce69b4d6d..a7bed3709d 100644 --- a/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java @@ -346,8 +346,8 @@ public class StaticTopicIT extends BaseConf { RMQNormalConsumer consumer = getConsumer(nsAddr, group, topic, "*", new RMQNormalListener()); long start = System.currentTimeMillis(); - int queueNum = 10; - int msgEachQueue = 100; + int queueNum = 5; + int msgEachQueue = 10; //create static topic { Set targetBrokers = ImmutableSet.of(broker1Name); From 947ffe4b9cc10136bf0a51e933e3a4947cfa9166 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 23 Jun 2022 15:31:02 +0800 Subject: [PATCH 273/338] [ISSUE #3949] Fix npe --- .../v2/consumer/ReceiveMessageActivity.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 48bc1b1f83..490fcd57bc 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -27,6 +27,7 @@ import io.grpc.stub.StreamObserver; import java.time.Duration; import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.constant.ConsumeInitMode; import org.apache.rocketmq.common.filter.FilterAPI; import org.apache.rocketmq.common.message.MessageConst; @@ -114,14 +115,16 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { timeRemaining ).thenAccept(popResult -> { if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { - List messageExtList = popResult.getMsgFoundList(); - for (MessageExt messageExt : messageExtList) { - String receiptHandle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); - if (receiptHandle != null) { - MessageReceiptHandle messageReceiptHandle = - new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), - messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); - receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, messageExt.getMsgId(), receiptHandle, messageReceiptHandle); + if (PopStatus.FOUND.equals(popResult.getPopStatus())) { + List messageExtList = popResult.getMsgFoundList(); + for (MessageExt messageExt : messageExtList) { + String receiptHandle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (receiptHandle != null) { + MessageReceiptHandle messageReceiptHandle = + new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), + messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); + receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, messageExt.getMsgId(), receiptHandle, messageReceiptHandle); + } } } } From 04a256bd3227c60b6226175cc3b78105b9bb3c1e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 27 Jun 2022 20:08:44 +0800 Subject: [PATCH 274/338] [ISSUE #3949] not to encode data in transactionId; save transaction data in mem --- ...ractTransactionalMessageCheckListener.java | 1 - .../CheckTransactionStateRequestHeader.java | 10 - .../proxy/common/utils/ProxyUtils.java | 2 + .../rocketmq/proxy/config/ProxyConfig.java | 27 ++ .../grpc/v2/channel/GrpcClientChannel.java | 28 +- .../proxy/grpc/v2/client/ClientActivity.java | 6 + .../transaction/EndTransactionActivity.java | 4 +- .../processor/DefaultMessagingProcessor.java | 5 +- .../proxy/processor/MessagingProcessor.java | 5 +- .../proxy/processor/ProducerProcessor.java | 30 ++- .../proxy/processor/TransactionProcessor.java | 45 ++-- .../proxy/service/ClusterServiceManager.java | 24 +- .../proxy/service/LocalServiceManager.java | 4 +- .../message/ClusterMessageService.java | 6 +- .../service/message/LocalMessageService.java | 7 +- .../proxy/service/message/MessageService.java | 3 +- .../ProxyClientRemotingProcessor.java | 3 + .../relay/AbstractProxyRelayService.java | 59 +++++ .../relay/ClusterProxyRelayService.java | 7 +- .../service/relay/LocalProxyRelayService.java | 6 +- .../proxy/service/relay/ProxyChannel.java | 14 +- .../service/relay/ProxyRelayService.java | 10 + .../proxy/service/relay/RelayData.java | 47 ++++ .../AbstractTransactionService.java | 104 ++++++++ .../ClusterTransactionService.java | 23 +- .../EndTransactionRequestData.java | 46 ++++ .../transaction/LocalTransactionService.java | 15 +- .../service/transaction/TransactionData.java | 111 ++++++++ .../transaction/TransactionDataManager.java | 156 +++++++++++ .../service/transaction/TransactionId.java | 245 ------------------ .../transaction/TransactionService.java | 13 + .../EndTransactionActivityTest.java | 5 +- .../processor/ProducerProcessorTest.java | 53 +++- .../processor/TransactionProcessorTest.java | 27 +- .../relay/LocalProxyRelayServiceTest.java | 5 +- .../proxy/service/relay/ProxyChannelTest.java | 9 +- .../AbstractTransactionServiceTest.java | 135 ++++++++++ .../TransactionDataManagerTest.java | 137 ++++++++++ .../transaction/TransactionIdTest.java | 69 ----- 39 files changed, 1060 insertions(+), 446 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/RelayData.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/EndTransactionRequestData.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java delete mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java delete mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java 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 613fe0f589..2ed0d9d1cd 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 @@ -56,7 +56,6 @@ public abstract class AbstractTransactionalMessageCheckListener { checkTransactionStateRequestHeader.setMsgId(msgExt.getUserProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX)); checkTransactionStateRequestHeader.setTransactionId(checkTransactionStateRequestHeader.getMsgId()); checkTransactionStateRequestHeader.setTranStateTableOffset(msgExt.getQueueOffset()); - checkTransactionStateRequestHeader.setBrokerName(brokerController.getBrokerConfig().getBrokerName()); msgExt.setTopic(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_TOPIC)); msgExt.setQueueId(Integer.parseInt(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_QUEUE_ID))); msgExt.setStoreSize(0); diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java index b04f7ef812..d62802c06a 100644 --- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java +++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/CheckTransactionStateRequestHeader.java @@ -26,7 +26,6 @@ import org.apache.rocketmq.remoting.annotation.CFNotNull; import org.apache.rocketmq.remoting.exception.RemotingCommandException; public class CheckTransactionStateRequestHeader implements CommandCustomHeader { - private String brokerName; @CFNotNull private Long tranStateTableOffset; @CFNotNull @@ -39,14 +38,6 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { public void checkFields() throws RemotingCommandException { } - public String getBrokerName() { - return brokerName; - } - - public void setBrokerName(String brokerName) { - this.brokerName = brokerName; - } - public Long getTranStateTableOffset() { return tranStateTableOffset; } @@ -90,7 +81,6 @@ public class CheckTransactionStateRequestHeader implements CommandCustomHeader { @Override public String toString() { return MoreObjects.toStringHelper(this) - .add("brokerName", brokerName) .add("tranStateTableOffset", tranStateTableOffset) .add("commitLogOffset", commitLogOffset) .add("msgId", msgId) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java index 61eb131ee2..7e82a49613 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ProxyUtils.java @@ -19,4 +19,6 @@ package org.apache.rocketmq.proxy.common.utils; public class ProxyUtils { public static final int MAX_MSG_NUMS_FOR_POP_REQUEST = 32; + + public static final String BROKER_ADDR = "brokerAddr"; } 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 1eb3f90009..84aececd30 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 @@ -95,6 +95,9 @@ public class ProxyConfig { private int transactionHeartbeatThreadPoolQueueCapacity = 200; private int transactionHeartbeatPeriodSecond = 20; private int transactionHeartbeatBatchNum = 100; + private long transactionDataExpireScanPeriodMillis = Duration.ofSeconds(10).toMillis(); + private long transactionDataMaxWaitClearMillis = Duration.ofSeconds(30).toMillis(); + private long defaultTransactionCheckImmunityTimeInMills = Duration.ofMillis(1).toMillis(); private long longPollingReserveTimeInMillis = 100; @@ -520,6 +523,30 @@ public class ProxyConfig { this.transactionHeartbeatBatchNum = transactionHeartbeatBatchNum; } + public long getTransactionDataExpireScanPeriodMillis() { + return transactionDataExpireScanPeriodMillis; + } + + public void setTransactionDataExpireScanPeriodMillis(long transactionDataExpireScanPeriodMillis) { + this.transactionDataExpireScanPeriodMillis = transactionDataExpireScanPeriodMillis; + } + + public long getTransactionDataMaxWaitClearMillis() { + return transactionDataMaxWaitClearMillis; + } + + public void setTransactionDataMaxWaitClearMillis(long transactionDataMaxWaitClearMillis) { + this.transactionDataMaxWaitClearMillis = transactionDataMaxWaitClearMillis; + } + + public long getDefaultTransactionCheckImmunityTimeInMills() { + return defaultTransactionCheckImmunityTimeInMills; + } + + public void setDefaultTransactionCheckImmunityTimeInMills(long defaultTransactionCheckImmunityTimeInMills) { + this.defaultTransactionCheckImmunityTimeInMills = defaultTransactionCheckImmunityTimeInMills; + } + public long getLongPollingReserveTimeInMillis() { return longPollingReserveTimeInMillis; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 1d74dc9dff..04d93af519 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -36,7 +36,7 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.service.relay.ProxyChannel; import org.apache.rocketmq.proxy.service.relay.ProxyRelayResult; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class GrpcClientChannel extends ProxyChannel { @@ -127,15 +127,23 @@ public class GrpcClientChannel extends ProxyChannel { @Override protected CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, - MessageExt messageExt, TransactionId transactionId) { - this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() - .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() - .setTransactionId(transactionId.getProxyTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) - .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, header.getBrokerName())) - .build()) - .build()); - return CompletableFuture.completedFuture(null); + MessageExt messageExt, TransactionData transactionData, CompletableFuture> responseFuture) { + CompletableFuture writeFuture = new CompletableFuture<>(); + try { + this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() + .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() + .setTransactionId(transactionData.getTransactionId()) + .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) + .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, transactionData.getBrokerName())) + .build()) + .build()); + responseFuture.complete(null); + writeFuture.complete(null); + } catch (Throwable t) { + responseFuture.completeExceptionally(t); + writeFuture.completeExceptionally(t); + } + return writeFuture; } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 787ee61937..966c0583c1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -96,6 +96,12 @@ public class ClientActivity extends AbstractMessingActivity { LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); Settings clientSettings = grpcClientSettingsManager.getClientSettings(ctx); + if (clientSettings == null) { + future.complete(HeartbeatResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, "cannot find client settings for this client")) + .build()); + return future; + } switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index cc5e7f5343..46eb3e337a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -30,7 +30,6 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.TransactionStatus; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; public class EndTransactionActivity extends AbstractMessingActivity { @@ -42,7 +41,6 @@ public class EndTransactionActivity extends AbstractMessingActivity { public CompletableFuture endTransaction(ProxyContext ctx, EndTransactionRequest request) { CompletableFuture future = new CompletableFuture<>(); try { - TransactionId transactionId = TransactionId.decode(request.getTransactionId()); TransactionStatus transactionStatus = TransactionStatus.UNKNOWN; TransactionResolution transactionResolution = request.getResolution(); switch (transactionResolution) { @@ -57,7 +55,7 @@ public class EndTransactionActivity extends AbstractMessingActivity { } this.messagingProcessor.endTransaction( ctx, - transactionId, + request.getTransactionId(), request.getMessageId(), GrpcConverter.wrapResourceWithNamespace(request.getTopic()), transactionStatus, 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 3dc3afab04..07aae54191 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 @@ -51,7 +51,6 @@ import org.apache.rocketmq.proxy.service.ServiceManagerFactory; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -141,8 +140,8 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId, - String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, + public void endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, + TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { this.transactionProcessor.endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, 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 70d994c2dc..5320426d58 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 @@ -44,7 +44,6 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -103,7 +102,7 @@ public interface MessagingProcessor extends StartAndShutdown { default void endTransaction( ProxyContext ctx, - TransactionId transactionId, + String transactionId, String messageId, String producerGroup, TransactionStatus transactionStatus, @@ -114,7 +113,7 @@ public interface MessagingProcessor extends StartAndShutdown { void endTransaction( ProxyContext ctx, - TransactionId transactionId, + String transactionId, String messageId, String producerGroup, TransactionStatus transactionStatus, 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 7586c9b401..9362580887 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 @@ -24,16 +24,20 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; +import org.apache.rocketmq.common.message.MessageId; import org.apache.rocketmq.common.protocol.NamespaceUtil; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; @@ -43,11 +47,10 @@ import org.apache.rocketmq.proxy.processor.validator.DefaultTopicMessageTypeVali import org.apache.rocketmq.proxy.processor.validator.TopicMessageTypeValidator; import org.apache.rocketmq.proxy.service.ServiceManager; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ProducerProcessor extends AbstractProcessor { - + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private final ExecutorService executor; private final TopicMessageTypeValidator topicMessageTypeValidator; @@ -94,8 +97,7 @@ public class ProducerProcessor extends AbstractProcessor { if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && StringUtils.isNotBlank(sendResult.getTransactionId())) { - TransactionId transactionId = TransactionId.genByBrokerTransactionId(messageQueue.getBrokerName(), sendResult); - sendResult.setTransactionId(transactionId.getProxyTransactionId()); + fillTransactionData(messageQueue, sendResult, messageList); } } return sendResultList; @@ -106,6 +108,26 @@ public class ProducerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } + protected void fillTransactionData(AddressableMessageQueue messageQueue, SendResult sendResult, List messageList) { + try { + MessageId id; + if (sendResult.getOffsetMsgId() != null) { + id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); + } else { + id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); + } + this.serviceManager.getTransactionService().addTransactionDataByBrokerName( + messageQueue.getBrokerName(), + sendResult.getQueueOffset(), + id.getOffset(), + sendResult.getTransactionId(), + messageList.get(0) + ); + } catch (Throwable t) { + log.warn("fillTransactionData failed. messageQueue: {}, sendResult: {}", messageQueue, sendResult, t); + } + } + protected SendMessageRequestHeader buildSendMessageRequestHeader(List messageList, String producerGroup, int sysFlag, int queueId) { SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java index 138c38761b..76517861e9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java @@ -17,11 +17,10 @@ package org.apache.rocketmq.proxy.processor; import org.apache.rocketmq.client.exception.MQBrokerException; -import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.ServiceManager; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.EndTransactionRequestData; import org.apache.rocketmq.remoting.exception.RemotingException; public class TransactionProcessor extends AbstractProcessor { @@ -31,45 +30,37 @@ public class TransactionProcessor extends AbstractProcessor { super(messagingProcessor, serviceManager); } - void endTransaction(ProxyContext ctx, TransactionId transactionId, String messageId, String producerGroup, + void endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { - EndTransactionRequestHeader requestHeader = buildEndTransactionRequestHeader(transactionId, messageId, - producerGroup, transactionStatus, fromTransactionCheck); + EndTransactionRequestData headerData = serviceManager.getTransactionService().genEndTransactionRequestHeader( + producerGroup, + buildCommitOrRollback(transactionStatus), + fromTransactionCheck, + messageId, + transactionId + ); + if (headerData == null) { + return; + } this.serviceManager.getMessageService().endTransactionOneway( ctx, - transactionId, - requestHeader, + headerData.getBrokerName(), + headerData.getRequestHeader(), timeoutMillis ); } - protected EndTransactionRequestHeader buildEndTransactionRequestHeader(TransactionId transactionId, - String messageId, String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck) { - int commitOrRollback; + protected int buildCommitOrRollback(TransactionStatus transactionStatus) { switch (transactionStatus) { case COMMIT: - commitOrRollback = MessageSysFlag.TRANSACTION_COMMIT_TYPE; - break; + return MessageSysFlag.TRANSACTION_COMMIT_TYPE; case ROLLBACK: - commitOrRollback = MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; - break; + return MessageSysFlag.TRANSACTION_ROLLBACK_TYPE; default: - commitOrRollback = MessageSysFlag.TRANSACTION_NOT_TYPE; - break; + return MessageSysFlag.TRANSACTION_NOT_TYPE; } - - EndTransactionRequestHeader endTransactionRequestHeader = new EndTransactionRequestHeader(); - endTransactionRequestHeader.setProducerGroup(producerGroup); - endTransactionRequestHeader.setMsgId(messageId); - endTransactionRequestHeader.setTransactionId(transactionId.getBrokerTransactionId()); - endTransactionRequestHeader.setTranStateTableOffset(transactionId.getTranStateTableOffset()); - endTransactionRequestHeader.setCommitLogOffset(transactionId.getCommitLogOffset()); - endTransactionRequestHeader.setCommitOrRollback(commitOrRollback); - endTransactionRequestHeader.setFromTransactionCheck(fromTransactionCheck); - - return endTransactionRequestHeader; } public void addTransactionSubscription(ProxyContext ctx, String producerGroup, String topic) { 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 45a8d7cec6..f0e0c98fb5 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 @@ -50,18 +50,18 @@ import org.apache.rocketmq.remoting.RPCHook; public class ClusterServiceManager extends AbstractStartAndShutdown implements ServiceManager { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - private final ClusterTransactionService clusterTransactionService; - private final ProducerManager producerManager; - private final ConsumerManager consumerManager; - private final TopicRouteService topicRouteService; - private final MessageService messageService; - private final ProxyRelayService proxyRelayService; - private final ClusterMetadataService metadataService; + protected ClusterTransactionService clusterTransactionService; + protected ProducerManager producerManager; + protected ConsumerManager consumerManager; + protected TopicRouteService topicRouteService; + protected MessageService messageService; + protected ProxyRelayService proxyRelayService; + protected ClusterMetadataService metadataService; - protected final ScheduledExecutorService scheduledExecutorService; - protected final MQClientAPIFactory messagingClientAPIFactory; - protected final MQClientAPIFactory operationClientAPIFactory; - protected final MQClientAPIFactory transactionClientAPIFactory; + protected ScheduledExecutorService scheduledExecutorService; + protected MQClientAPIFactory messagingClientAPIFactory; + protected MQClientAPIFactory operationClientAPIFactory; + protected MQClientAPIFactory transactionClientAPIFactory; public ClusterServiceManager(RPCHook rpcHook) { this.scheduledExecutorService = Executors.newScheduledThreadPool(3); @@ -93,7 +93,7 @@ public class ClusterServiceManager extends AbstractStartAndShutdown implements S this.messageService = new ClusterMessageService(this.topicRouteService, this.messagingClientAPIFactory); this.clusterTransactionService = new ClusterTransactionService(this.topicRouteService, this.producerManager, rpcHook, this.transactionClientAPIFactory); - this.proxyRelayService = new ClusterProxyRelayService(); + this.proxyRelayService = new ClusterProxyRelayService(this.clusterTransactionService); this.metadataService = new ClusterMetadataService(topicRouteService, operationClientAPIFactory); this.init(); 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 c69b6773a0..6afc86c578 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 @@ -67,8 +67,8 @@ public class LocalServiceManager extends AbstractStartAndShutdown implements Ser scheduledExecutorService ); this.topicRouteService = new LocalTopicRouteService(brokerController, mqClientAPIFactory); - this.transactionService = new LocalTransactionService(); - this.proxyRelayService = new LocalProxyRelayService(brokerController); + this.transactionService = new LocalTransactionService(brokerController.getBrokerConfig()); + this.proxyRelayService = new LocalProxyRelayService(brokerController, this.transactionService); this.metadataService = new LocalMetadataService(brokerController); this.init(); } 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 cc32143c08..6f710e10cc 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 @@ -47,7 +47,6 @@ import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.route.TopicRouteService; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -89,11 +88,10 @@ public class ClusterMessageService implements MessageService { } @Override - public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, - EndTransactionRequestHeader requestHeader, + public void endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { this.mqClientAPIFactory.getClient().endTransactionOneway( - this.resolveBrokerAddr(transactionId.getBrokerName()), + this.resolveBrokerAddr(brokerName), requestHeader, "end transaction from proxy", 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 8de11b87e8..6b093bb0c9 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 @@ -32,6 +32,7 @@ import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.client.consumer.PullResult; +import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.constant.LoggerName; @@ -69,8 +70,8 @@ import org.apache.rocketmq.proxy.service.channel.ChannelManager; import org.apache.rocketmq.proxy.service.channel.InvocationContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -174,8 +175,8 @@ public class LocalMessageService implements MessageService { } @Override - public void endTransactionOneway(ProxyContext ctx, TransactionId transactionId, - EndTransactionRequestHeader requestHeader, long timeoutMillis) { + public void endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, + long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { SimpleChannel channel = channelManager.createChannel(ctx); ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); 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 45ffce4933..5b63aa284c 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 @@ -42,7 +42,6 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -66,7 +65,7 @@ public interface MessageService { void endTransactionOneway( ProxyContext ctx, - TransactionId transactionId, + String brokerName, EndTransactionRequestHeader requestHeader, long timeoutMillis ) throws MQBrokerException, RemotingException, InterruptedException; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java index d932cd1596..9fdba52c37 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/ProxyClientRemotingProcessor.java @@ -25,6 +25,8 @@ import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -56,6 +58,7 @@ public class ProxyClientRemotingProcessor extends ClientRemotingProcessor { CheckTransactionStateRequestHeader requestHeader = request.decodeCommandCustomHeader(CheckTransactionStateRequestHeader.class); request.writeCustomHeader(requestHeader); + request.addExtField(ProxyUtils.BROKER_ADDR, RemotingUtil.socketAddress2String(ctx.channel().remoteAddress())); this.producerManager.getAvailableChannel(group).writeAndFlush(request); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java new file mode 100644 index 0000000000..5b919681a5 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.relay; + +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; +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.utils.ProxyUtils; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; +import org.apache.rocketmq.remoting.protocol.RemotingCommand; + +public abstract class AbstractProxyRelayService implements ProxyRelayService { + + protected final TransactionService transactionService; + + public AbstractProxyRelayService(TransactionService transactionService) { + this.transactionService = transactionService; + } + + @Override + public RelayData processCheckTransactionState(ProxyContext context, + RemotingCommand command, CheckTransactionStateRequestHeader header, MessageExt messageExt) { + CompletableFuture> future = new CompletableFuture<>(); + TransactionData transactionData = transactionService.addTransactionDataByBrokerAddr( + command.getExtFields().get(ProxyUtils.BROKER_ADDR), + header.getTranStateTableOffset(), + header.getCommitLogOffset(), + header.getTransactionId(), + messageExt); + if (transactionData == null) { + throw new ProxyException(ProxyExceptionCode.INTERNAL_SERVER_ERROR, + String.format("add transaction data failed. request:%s, message:%s", command, messageExt)); + } + future.exceptionally(throwable -> { + this.transactionService.onSendCheckTransactionStateFailed(context, transactionData); + return null; + }); + return new RelayData<>(transactionData, future); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java index fd7afaec9a..65ffeeb657 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ClusterProxyRelayService.java @@ -22,12 +22,17 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.protocol.RemotingCommand; /** * not implement yet */ -public class ClusterProxyRelayService implements ProxyRelayService { +public class ClusterProxyRelayService extends AbstractProxyRelayService { + + public ClusterProxyRelayService(TransactionService transactionService) { + super(transactionService); + } @Override public CompletableFuture> processGetConsumerRunningInfo( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java index acfb62a87b..35aa5d073c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayService.java @@ -25,15 +25,17 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract; import org.apache.rocketmq.remoting.protocol.RemotingCommand; -public class LocalProxyRelayService implements ProxyRelayService { +public class LocalProxyRelayService extends AbstractProxyRelayService { private final BrokerController brokerController; - public LocalProxyRelayService(BrokerController brokerController) { + public LocalProxyRelayService(BrokerController brokerController, TransactionService transactionService) { + super(transactionService); this.brokerController = brokerController; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index 26ade3c128..a9b205a3fb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -42,7 +42,7 @@ import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -83,9 +83,8 @@ public abstract class ProxyChannel extends SimpleChannel { case RequestCode.CHECK_TRANSACTION_STATE: { CheckTransactionStateRequestHeader header = (CheckTransactionStateRequestHeader) command.readCustomHeader(); MessageExt messageExt = MessageDecoder.decode(ByteBuffer.wrap(command.getBody()), true, false, false); - TransactionId transactionId = TransactionId.genByBrokerTransactionId(header.getBrokerName(), - header.getTransactionId(), messageExt.getCommitLogOffset(), messageExt.getQueueOffset()); - processFuture = this.processCheckTransaction(header, messageExt, transactionId); + RelayData relayData = this.proxyRelayService.processCheckTransactionState(context, command, header, messageExt); + processFuture = this.processCheckTransaction(header, messageExt, relayData.getProcessResult(), relayData.getRelayFuture()); break; } case RequestCode.GET_CONSUMER_RUNNING_INFO: { @@ -123,8 +122,11 @@ public abstract class ProxyChannel extends SimpleChannel { protected abstract CompletableFuture processOtherMessage(Object msg); - protected abstract CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, - MessageExt messageExt, TransactionId transactionId); + protected abstract CompletableFuture processCheckTransaction( + CheckTransactionStateRequestHeader header, + MessageExt messageExt, + TransactionData transactionData, + CompletableFuture> responseFuture); protected abstract CompletableFuture processGetConsumerRunningInfo( RemotingCommand command, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java index b7284da1c0..9785f14ddd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyRelayService.java @@ -17,11 +17,14 @@ package org.apache.rocketmq.proxy.service.relay; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult; import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; +import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface ProxyRelayService { @@ -37,4 +40,11 @@ public interface ProxyRelayService { RemotingCommand command, ConsumeMessageDirectlyResultRequestHeader header ); + + RelayData processCheckTransactionState( + ProxyContext context, + RemotingCommand command, + CheckTransactionStateRequestHeader header, + MessageExt messageExt + ); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/RelayData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/RelayData.java new file mode 100644 index 0000000000..20ee0f5fdf --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/RelayData.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.relay; + +import java.util.concurrent.CompletableFuture; + +public class RelayData { + private T processResult; + private CompletableFuture> relayFuture; + + public RelayData(T processResult, CompletableFuture> relayFuture) { + this.processResult = processResult; + this.relayFuture = relayFuture; + } + + public CompletableFuture> getRelayFuture() { + return relayFuture; + } + + public void setRelayFuture( + CompletableFuture> relayFuture) { + this.relayFuture = relayFuture; + } + + public T getProcessResult() { + return processResult; + } + + public void setProcessResult(T processResult) { + this.processResult = processResult; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java new file mode 100644 index 0000000000..5075ac0fda --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.transaction; + +import java.time.Duration; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; + +public abstract class AbstractTransactionService implements TransactionService, StartAndShutdown { + + protected TransactionDataManager transactionDataManager = new TransactionDataManager(); + + @Override + public TransactionData addTransactionDataByBrokerAddr(String brokerAddr, long tranStateTableOffset, long commitLogOffset, String transactionId, + Message message) { + return this.addTransactionDataByBrokerName(this.getBrokerNameByAddr(brokerAddr), tranStateTableOffset, commitLogOffset, transactionId, message); + } + + @Override + public TransactionData addTransactionDataByBrokerName(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, + Message message) { + if (StringUtils.isBlank(brokerName)) { + return null; + } + long checkImmunityTime = parseCheckImmunityTime(message); + TransactionData transactionData = new TransactionData( + brokerName, + tranStateTableOffset, commitLogOffset, transactionId, + System.currentTimeMillis(), checkImmunityTime); + + this.transactionDataManager.addTransactionData( + transactionId, + transactionData + ); + return transactionData; + } + + @Override + public EndTransactionRequestData genEndTransactionRequestHeader(String producerGroup, Integer commitOrRollback, + boolean fromTransactionCheck, String msgId, String transactionId) { + TransactionData transactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(transactionId); + if (transactionData == null) { + return null; + } + EndTransactionRequestHeader header = new EndTransactionRequestHeader(); + header.setProducerGroup(producerGroup); + header.setCommitOrRollback(commitOrRollback); + header.setFromTransactionCheck(fromTransactionCheck); + header.setMsgId(msgId); + header.setTransactionId(transactionId); + header.setTranStateTableOffset(transactionData.getTranStateTableOffset()); + header.setCommitLogOffset(transactionData.getCommitLogOffset()); + return new EndTransactionRequestData(transactionData.getBrokerName(), header); + } + + @Override + public void onSendCheckTransactionStateFailed(ProxyContext context, TransactionData transactionData) { + this.transactionDataManager.removeTransactionData(transactionData.getTransactionId(), transactionData); + } + + protected long parseCheckImmunityTime(Message message) { + long checkImmunityTime = ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInMills(); + String checkImmunityTimeStr = message.getProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS); + if (StringUtils.isNotBlank(checkImmunityTimeStr)) { + try { + checkImmunityTime = Duration.ofSeconds(Long.parseLong(checkImmunityTimeStr)).toMillis(); + } catch (Exception ignored) { + } + } + return checkImmunityTime; + } + + protected abstract String getBrokerNameByAddr(String brokerAddr); + + @Override + public void shutdown() throws Exception { + this.transactionDataManager.shutdown(); + } + + @Override + public void start() throws Exception { + this.transactionDataManager.start(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java index fd0943f657..48cdab33d1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/ClusterTransactionService.java @@ -28,6 +28,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.broker.client.ProducerManager; import org.apache.rocketmq.common.ServiceThread; import org.apache.rocketmq.common.constant.LoggerName; @@ -37,7 +39,6 @@ import org.apache.rocketmq.common.protocol.route.BrokerData; import org.apache.rocketmq.common.thread.ThreadPoolMonitor; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; @@ -45,7 +46,7 @@ import org.apache.rocketmq.proxy.service.route.MessageQueueView; import org.apache.rocketmq.proxy.service.route.TopicRouteService; import org.apache.rocketmq.remoting.RPCHook; -public class ClusterTransactionService implements StartAndShutdown, TransactionService { +public class ClusterTransactionService extends AbstractTransactionService { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); private static final String TRANS_HEARTBEAT_CLIENT_ID = "rmq-proxy-producer-client"; @@ -55,6 +56,7 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS private ThreadPoolExecutor heartbeatExecutors; private final Map/* cluster list */> groupClusterData = new ConcurrentHashMap<>(); + private final AtomicReference> brokerAddrNameMapRef = new AtomicReference<>(); private TxHeartbeatServiceThread txHeartbeatServiceThread; public ClusterTransactionService(TopicRouteService topicRouteService, ProducerManager producerManager, @@ -180,12 +182,14 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS if (heartbeatDataList == null) { return; } + Map brokerAddrNameMap = new ConcurrentHashMap<>(); for (HeartbeatData heartbeatData : heartbeatDataList) { - sendHeartBeatToCluster(clusterName, heartbeatData); + sendHeartBeatToCluster(clusterName, heartbeatData, brokerAddrNameMap); } + this.brokerAddrNameMapRef.set(brokerAddrNameMap); } - protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData) { + protected void sendHeartBeatToCluster(String clusterName, HeartbeatData heartbeatData, Map brokerAddrNameMap) { try { MessageQueueView messageQueue = this.topicRouteService.getAllMessageQueueView(clusterName); List brokerDataList = messageQueue.getTopicRouteData().getBrokerDatas(); @@ -193,6 +197,7 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS return; } for (BrokerData brokerData : brokerDataList) { + brokerAddrNameMap.put(brokerData.selectBrokerAddr(), brokerData.getBrokerName()); heartbeatExecutors.submit(() -> { String brokerAddr = brokerData.selectBrokerAddr(); this.mqClientAPIFactory.getClient() @@ -208,6 +213,14 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS } } + @Override + protected String getBrokerNameByAddr(String brokerAddr) { + if (StringUtils.isBlank(brokerAddr)) { + return null; + } + return brokerAddrNameMapRef.get().get(brokerAddr); + } + static class ClusterData { private final String cluster; @@ -263,6 +276,7 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); txHeartbeatServiceThread = new TxHeartbeatServiceThread(); + super.start(); txHeartbeatServiceThread.start(); heartbeatExecutors = ThreadPoolMonitor.createAndMonitor( proxyConfig.getTransactionHeartbeatThreadPoolNums(), @@ -277,5 +291,6 @@ public class ClusterTransactionService implements StartAndShutdown, TransactionS public void shutdown() throws Exception { txHeartbeatServiceThread.shutdown(); heartbeatExecutors.shutdown(); + super.shutdown(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/EndTransactionRequestData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/EndTransactionRequestData.java new file mode 100644 index 0000000000..b38b4335f4 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/EndTransactionRequestData.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.transaction; + +import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; + +public class EndTransactionRequestData { + private String brokerName; + private EndTransactionRequestHeader requestHeader; + + public EndTransactionRequestData(String brokerName, EndTransactionRequestHeader requestHeader) { + this.brokerName = brokerName; + this.requestHeader = requestHeader; + } + + public String getBrokerName() { + return brokerName; + } + + public void setBrokerName(String brokerName) { + this.brokerName = brokerName; + } + + public EndTransactionRequestHeader getRequestHeader() { + return requestHeader; + } + + public void setRequestHeader(EndTransactionRequestHeader requestHeader) { + this.requestHeader = requestHeader; + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java index fe0a1c0451..2371b25a24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/LocalTransactionService.java @@ -17,11 +17,19 @@ package org.apache.rocketmq.proxy.service.transaction; import java.util.List; +import org.apache.rocketmq.common.BrokerConfig; /** * no need to implements, because the channel of producer will put into the broker's producerManager */ -public class LocalTransactionService implements TransactionService { +public class LocalTransactionService extends AbstractTransactionService { + + protected final BrokerConfig brokerConfig; + + public LocalTransactionService(BrokerConfig brokerConfig) { + this.brokerConfig = brokerConfig; + } + @Override public void addTransactionSubscription(String group, List topicList) { @@ -41,4 +49,9 @@ public class LocalTransactionService implements TransactionService { public void unSubscribeAllTransactionTopic(String group) { } + + @Override + protected String getBrokerNameByAddr(String brokerAddr) { + return this.brokerConfig.getBrokerName(); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java new file mode 100644 index 0000000000..98770a218c --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.transaction; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.collect.ComparisonChain; + +public class TransactionData implements Comparable { + private final String brokerName; + private final long tranStateTableOffset; + private final long commitLogOffset; + private final String transactionId; + private final long checkTimestamp; + private final long checkImmunityTime; + + public TransactionData(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, + long checkTimestamp, long checkImmunityTime) { + this.brokerName = brokerName; + this.tranStateTableOffset = tranStateTableOffset; + this.commitLogOffset = commitLogOffset; + this.transactionId = transactionId; + this.checkTimestamp = checkTimestamp; + this.checkImmunityTime = checkImmunityTime; + } + + public String getBrokerName() { + return brokerName; + } + + public long getTranStateTableOffset() { + return tranStateTableOffset; + } + + public long getCommitLogOffset() { + return commitLogOffset; + } + + public String getTransactionId() { + return transactionId; + } + + public long getCheckTimestamp() { + return checkTimestamp; + } + + public long getCheckImmunityTime() { + return checkImmunityTime; + } + + public long getExpireTime() { + return checkTimestamp + checkImmunityTime; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionData data = (TransactionData) o; + return tranStateTableOffset == data.tranStateTableOffset && commitLogOffset == data.commitLogOffset && + getExpireTime() == data.getExpireTime() && Objects.equal(brokerName, data.brokerName) && + Objects.equal(transactionId, data.transactionId); + } + + @Override + public int hashCode() { + return Objects.hashCode(brokerName, transactionId, tranStateTableOffset, commitLogOffset, getExpireTime()); + } + + @Override + public int compareTo(TransactionData o) { + return ComparisonChain.start() + .compare(getExpireTime(), o.getExpireTime()) + .compare(brokerName, o.brokerName) + .compare(commitLogOffset, o.commitLogOffset) + .compare(tranStateTableOffset, o.tranStateTableOffset) + .compare(transactionId, o.transactionId) + .result(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("brokerName", brokerName) + .add("tranStateTableOffset", tranStateTableOffset) + .add("commitLogOffset", commitLogOffset) + .add("transactionId", transactionId) + .add("checkTimestamp", checkTimestamp) + .add("checkImmunityTime", checkImmunityTime) + .toString(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java new file mode 100644 index 0000000000..5b883f3dd0 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.transaction; + +import java.util.Iterator; +import java.util.Map; +import java.util.NavigableSet; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.rocketmq.common.ServiceThread; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.common.StartAndShutdown; +import org.apache.rocketmq.proxy.config.ConfigurationManager; + +public class TransactionDataManager implements StartAndShutdown { + private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + + protected final AtomicLong maxTransactionDataExpireTime = new AtomicLong(System.currentTimeMillis()); + protected final Map> transactionIdDataMap = new ConcurrentHashMap<>(); + protected final TransactionDataCleaner transactionDataCleaner = new TransactionDataCleaner(); + + public void addTransactionData(String transactionId, TransactionData transactionData) { + this.transactionIdDataMap.compute(transactionId, (transactionIdKey, dataSet) -> { + if (dataSet == null) { + dataSet = new ConcurrentSkipListSet<>(); + } + dataSet.add(transactionData); + return dataSet; + }); + } + + public TransactionData pollFirstNoExpireTransactionData(String transactionId) { + AtomicReference res = new AtomicReference<>(); + long currTimestamp = System.currentTimeMillis(); + this.transactionIdDataMap.computeIfPresent(transactionId, (transactionIdKey, dataSet) -> { + TransactionData data = dataSet.pollFirst(); + while (data != null && data.getExpireTime() < currTimestamp) { + data = dataSet.pollFirst(); + } + if (data != null) { + res.set(data); + } + if (dataSet.isEmpty()) { + return null; + } + return dataSet; + }); + return res.get(); + } + + public void removeTransactionData(String transactionId, TransactionData transactionData) { + this.transactionIdDataMap.computeIfPresent(transactionId, (transactionIdKey, dataSet) -> { + dataSet.remove(transactionData); + if (dataSet.isEmpty()) { + return null; + } + return dataSet; + }); + } + + protected void cleanExpireTransactionData() { + long currTimestamp = System.currentTimeMillis(); + Set transactionIdSet = this.transactionIdDataMap.keySet(); + for (String transactionId : transactionIdSet) { + this.transactionIdDataMap.computeIfPresent(transactionId, (transactionIdKey, dataSet) -> { + Iterator iterator = dataSet.iterator(); + while (iterator.hasNext()) { + try { + TransactionData data = iterator.next(); + if (data.getExpireTime() < currTimestamp) { + iterator.remove(); + } else { + break; + } + } catch (NoSuchElementException ignore) { + break; + } + } + if (dataSet.isEmpty()) { + return null; + } + try { + TransactionData maxData = dataSet.last(); + maxTransactionDataExpireTime.set(Math.max(maxTransactionDataExpireTime.get(), maxData.getExpireTime())); + } catch (NoSuchElementException ignore) { + } + return dataSet; + }); + } + } + + protected class TransactionDataCleaner extends ServiceThread { + + @Override + public String getServiceName() { + return "TransactionDataCleaner"; + } + + @Override + public void run() { + log.info(this.getServiceName() + " service started"); + while (!this.isStopped()) { + this.waitForRunning(ConfigurationManager.getProxyConfig().getTransactionDataExpireScanPeriodMillis()); + } + log.info(this.getServiceName() + " service stopped"); + } + + @Override + protected void onWaitEnd() { + cleanExpireTransactionData(); + } + } + + protected void waitTransactionDataClear() throws InterruptedException { + this.cleanExpireTransactionData(); + long waitMs = Math.max(this.maxTransactionDataExpireTime.get() - System.currentTimeMillis(), 0); + waitMs = Math.min(waitMs, ConfigurationManager.getProxyConfig().getTransactionDataMaxWaitClearMillis()); + + if (waitMs > 0) { + TimeUnit.MILLISECONDS.sleep(waitMs); + } + } + + @Override + public void shutdown() throws Exception { + this.transactionDataCleaner.shutdown(); + this.waitTransactionDataClear(); + } + + @Override + public void start() throws Exception { + this.transactionDataCleaner.start(); + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java deleted file mode 100644 index 78b479634a..0000000000 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionId.java +++ /dev/null @@ -1,245 +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.proxy.service.transaction; - -import com.google.common.base.MoreObjects; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.common.UtilAll; -import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.message.MessageDecoder; -import org.apache.rocketmq.common.message.MessageId; -import org.apache.rocketmq.logging.InternalLogger; -import org.apache.rocketmq.logging.InternalLoggerFactory; - -public class TransactionId { - private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - - private String brokerName; - private String brokerTransactionId; - private long commitLogOffset; - private long tranStateTableOffset; - private String proxyTransactionId; - - public TransactionId( - String brokerName, - String brokerTransactionId, - long commitLogOffset, - long tranStateTableOffset, - String proxyTransactionId - ) { - this.brokerName = brokerName; - this.brokerTransactionId = brokerTransactionId; - this.commitLogOffset = commitLogOffset; - this.tranStateTableOffset = tranStateTableOffset; - this.proxyTransactionId = proxyTransactionId; - } - - public TransactionId() { - } - - public static TransactionId genByBrokerTransactionId(String brokerName, SendResult sendResult) { - long commitLogOffset = 0L; - try { - if (sendResult.getOffsetMsgId() != null) { - commitLogOffset = generateCommitLogOffset(sendResult.getOffsetMsgId()); - } else { - commitLogOffset = generateCommitLogOffset(sendResult.getMsgId()); - } - } catch (Exception e) { - log.warn("genFromBrokerTransactionId failed. brokerName: {}, sendResult: {}", brokerName, sendResult, e); - } - return genByBrokerTransactionId(brokerName, sendResult.getTransactionId(), - commitLogOffset, sendResult.getQueueOffset()); - } - - public static TransactionId genByBrokerTransactionId( - String brokerName, - String orgTransactionId, - long commitLogOffset, - long tranStateTableOffset - ) { - byte[] orgTransactionIdByte = new byte[0]; - if (StringUtils.isNotBlank(orgTransactionId)) { - orgTransactionIdByte = orgTransactionId.getBytes(StandardCharsets.UTF_8); - } - byte[] brokerNameByte = brokerName.getBytes(StandardCharsets.UTF_8); - - ByteBuffer byteBuffer = ByteBuffer.allocate(4 + brokerNameByte.length + 4 + orgTransactionIdByte.length + 8 + 8); - - byteBuffer.putInt(brokerNameByte.length); - byteBuffer.put(brokerNameByte); - byteBuffer.putInt(orgTransactionIdByte.length); - byteBuffer.put(orgTransactionIdByte); - byteBuffer.putLong(commitLogOffset); - byteBuffer.putLong(tranStateTableOffset); - - String gatewayTransactionId = UtilAll.bytes2string(byteBuffer.array()); - - return TransactionId.builder() - .brokerName(brokerName) - .brokerTransactionId(orgTransactionId) - .commitLogOffset(commitLogOffset) - .tranStateTableOffset(tranStateTableOffset) - .proxyTransactionId(gatewayTransactionId) - .build(); - } - - public static TransactionId decode(String transactionId) throws UnknownHostException { - ByteBuffer byteBuffer = ByteBuffer.wrap(UtilAll.string2bytes(transactionId)); - - int brokerNameLen = byteBuffer.getInt(); - byte[] brokerNameByte = new byte[brokerNameLen]; - byteBuffer.get(brokerNameByte); - - int orgTransactionIdLen = byteBuffer.getInt(); - byte[] orgTransactionIdByte = new byte[0]; - if (orgTransactionIdLen > 0) { - orgTransactionIdByte = new byte[orgTransactionIdLen]; - byteBuffer.get(orgTransactionIdByte); - } - - long commitLogOffset = byteBuffer.getLong(); - long tranStateTableOffset = byteBuffer.getLong(); - - return TransactionId.builder() - .brokerName(new String(brokerNameByte, StandardCharsets.UTF_8)) - .brokerTransactionId(new String(orgTransactionIdByte, StandardCharsets.UTF_8)) - .commitLogOffset(commitLogOffset) - .tranStateTableOffset(tranStateTableOffset) - .proxyTransactionId(transactionId) - .build(); - } - - public static long generateCommitLogOffset(String messageId) throws IllegalArgumentException { - try { - MessageId id = MessageDecoder.decodeMessageId(messageId); - return id.getOffset(); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("illegal messageId: " + messageId); - } - } - - public static TransactionIdBuilder builder() { - return new TransactionIdBuilder(); - } - - public String getBrokerName() { - return brokerName; - } - - public void setBrokerName(String brokerName) { - this.brokerName = brokerName; - } - - public String getBrokerTransactionId() { - return brokerTransactionId; - } - - public void setBrokerTransactionId(String brokerTransactionId) { - this.brokerTransactionId = brokerTransactionId; - } - - public long getCommitLogOffset() { - return commitLogOffset; - } - - public void setCommitLogOffset(long commitLogOffset) { - this.commitLogOffset = commitLogOffset; - } - - public long getTranStateTableOffset() { - return tranStateTableOffset; - } - - public void setTranStateTableOffset(long tranStateTableOffset) { - this.tranStateTableOffset = tranStateTableOffset; - } - - public String getProxyTransactionId() { - return proxyTransactionId; - } - - public void setProxyTransactionId(String proxyTransactionId) { - this.proxyTransactionId = proxyTransactionId; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("brokerName", brokerName) - .add("brokerTransactionId", brokerTransactionId) - .add("commitLogOffset", commitLogOffset) - .add("tranStateTableOffset", tranStateTableOffset) - .add("proxyTransactionId", proxyTransactionId) - .toString(); - } - - public static class TransactionIdBuilder { - private String brokerName; - private String brokerTransactionId; - private long commitLogOffset; - private long tranStateTableOffset; - private String proxyTransactionId; - - TransactionIdBuilder() { - } - - public TransactionIdBuilder brokerName(String brokerName) { - this.brokerName = brokerName; - return this; - } - - public TransactionIdBuilder brokerTransactionId(String brokerTransactionId) { - this.brokerTransactionId = brokerTransactionId; - return this; - } - - public TransactionIdBuilder commitLogOffset(long commitLogOffset) { - this.commitLogOffset = commitLogOffset; - return this; - } - - public TransactionIdBuilder tranStateTableOffset(long tranStateTableOffset) { - this.tranStateTableOffset = tranStateTableOffset; - return this; - } - - public TransactionIdBuilder proxyTransactionId(String proxyTransactionId) { - this.proxyTransactionId = proxyTransactionId; - return this; - } - - public TransactionId build() { - return new TransactionId(brokerName, brokerTransactionId, commitLogOffset, tranStateTableOffset, proxyTransactionId); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("brokerName", brokerName) - .add("brokerTransactionId", brokerTransactionId) - .add("commitLogOffset", commitLogOffset) - .add("tranStateTableOffset", tranStateTableOffset) - .add("proxyTransactionId", proxyTransactionId) - .toString(); - } - } -} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java index 75b83e98ac..8be2391f3d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java @@ -17,6 +17,8 @@ package org.apache.rocketmq.proxy.service.transaction; import java.util.List; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.proxy.common.ProxyContext; public interface TransactionService { @@ -27,4 +29,15 @@ public interface TransactionService { void replaceTransactionSubscription(String group, List topicList); void unSubscribeAllTransactionTopic(String group); + + TransactionData addTransactionDataByBrokerAddr(String brokerAddr, long tranStateTableOffset, long commitLogOffset, String transactionId, + Message message); + + TransactionData addTransactionDataByBrokerName(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, + Message message); + + EndTransactionRequestData genEndTransactionRequestHeader(String producerGroup, Integer commitOrRollback, + boolean fromTransactionCheck, String msgId, String transactionId); + + void onSendCheckTransactionStateFailed(ProxyContext context, TransactionData transactionData); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java index aa009ef7ae..3a6e46c486 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java @@ -28,7 +28,6 @@ import java.util.Collection; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.processor.TransactionStatus; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -77,9 +76,7 @@ public class EndTransactionActivityTest extends BaseActivityTest { .setResolution(resolution) .setTopic(Resource.newBuilder().setName("topic").build()) .setMessageId(MessageClientIDSetter.createUniqID()) - .setTransactionId( - TransactionId.genByBrokerTransactionId("brokerName", "0", 0, 0) - .getProxyTransactionId()) + .setTransactionId(MessageClientIDSetter.createUniqID()) .setSource(source) .build() ).get(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 89b8c36ea9..ec6c8845b6 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.processor; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -31,12 +32,14 @@ import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; +import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.assertj.core.util.Lists; import org.junit.Before; @@ -71,11 +74,15 @@ public class ProducerProcessorTest extends BaseProcessorTest { when(metadataService.getTopicMessageType(eq(TOPIC))).thenReturn(TopicMessageType.NORMAL); String txId = MessageClientIDSetter.createUniqID(); String msgId = MessageClientIDSetter.createUniqID(); + long commitLogOffset = 1000L; + long queueOffset = 100L; SendResult sendResult = new SendResult(); sendResult.setSendStatus(SendStatus.SEND_OK); sendResult.setTransactionId(txId); sendResult.setMsgId(msgId); + sendResult.setOffsetMsgId(createOffsetMsgId(commitLogOffset)); + sendResult.setQueueOffset(queueOffset); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); @@ -86,6 +93,15 @@ public class ProducerProcessorTest extends BaseProcessorTest { AddressableMessageQueue messageQueue = mock(AddressableMessageQueue.class); when(messageQueue.getBrokerName()).thenReturn("mockBroker"); + ArgumentCaptor brokerNameCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor tranStateTableOffsetCaptor = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor commitLogOffsetCaptor = ArgumentCaptor.forClass(Long.class); + when(transactionService.addTransactionDataByBrokerName( + brokerNameCaptor.capture(), + tranStateTableOffsetCaptor.capture(), + commitLogOffsetCaptor.capture(), + anyString(), any())).thenReturn(mock(TransactionData.class)); + List sendResultList = this.producerProcessor.sendMessage( createContext(), (ctx, messageQueueView) -> messageQueue, @@ -96,10 +112,9 @@ public class ProducerProcessorTest extends BaseProcessorTest { ).get(); assertNotNull(sendResultList); - TransactionId transactionId = TransactionId.decode(sendResultList.get(0).getTransactionId()); - assertNotNull(transactionId); - assertEquals(txId, transactionId.getBrokerTransactionId()); - assertEquals("mockBroker", transactionId.getBrokerName()); + assertEquals("mockBroker", brokerNameCaptor.getValue()); + assertEquals(queueOffset, tranStateTableOffsetCaptor.getValue().longValue()); + assertEquals(commitLogOffset, commitLogOffsetCaptor.getValue().longValue()); SendMessageRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); assertEquals(PRODUCER_GROUP, requestHeader.getProducerGroup()); @@ -110,11 +125,15 @@ public class ProducerProcessorTest extends BaseProcessorTest { public void testSendRetryMessage() throws Throwable { String txId = MessageClientIDSetter.createUniqID(); String msgId = MessageClientIDSetter.createUniqID(); + long commitLogOffset = 1000L; + long queueOffset = 100L; SendResult sendResult = new SendResult(); sendResult.setSendStatus(SendStatus.SEND_OK); sendResult.setTransactionId(txId); sendResult.setMsgId(msgId); + sendResult.setOffsetMsgId(createOffsetMsgId(commitLogOffset)); + sendResult.setQueueOffset(queueOffset); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(SendMessageRequestHeader.class); when(this.messageService.sendMessage(any(), any(), any(), requestHeaderArgumentCaptor.capture(), anyLong())) .thenReturn(CompletableFuture.completedFuture(Lists.newArrayList(sendResult))); @@ -127,6 +146,15 @@ public class ProducerProcessorTest extends BaseProcessorTest { AddressableMessageQueue messageQueue = mock(AddressableMessageQueue.class); when(messageQueue.getBrokerName()).thenReturn("mockBroker"); + ArgumentCaptor brokerNameCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor tranStateTableOffsetCaptor = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor commitLogOffsetCaptor = ArgumentCaptor.forClass(Long.class); + when(transactionService.addTransactionDataByBrokerName( + brokerNameCaptor.capture(), + tranStateTableOffsetCaptor.capture(), + commitLogOffsetCaptor.capture(), + anyString(), any())).thenReturn(mock(TransactionData.class)); + List sendResultList = this.producerProcessor.sendMessage( createContext(), (ctx, messageQueueView) -> messageQueue, @@ -137,10 +165,9 @@ public class ProducerProcessorTest extends BaseProcessorTest { ).get(); assertNotNull(sendResultList); - TransactionId transactionId = TransactionId.decode(sendResultList.get(0).getTransactionId()); - assertNotNull(transactionId); - assertEquals(txId, transactionId.getBrokerTransactionId()); - assertEquals("mockBroker", transactionId.getBrokerName()); + assertEquals("mockBroker", brokerNameCaptor.getValue()); + assertEquals(queueOffset, tranStateTableOffsetCaptor.getValue().longValue()); + assertEquals(commitLogOffset, commitLogOffsetCaptor.getValue().longValue()); SendMessageRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); assertEquals(PRODUCER_GROUP, requestHeader.getProducerGroup()); @@ -171,4 +198,12 @@ public class ProducerProcessorTest extends BaseProcessorTest { assertEquals(messageExt.getMsgId(), requestHeader.getOriginMsgId()); assertEquals(CONSUMER_GROUP, requestHeader.getGroup()); } + + private static String createOffsetMsgId(long commitLogOffset) { + int msgIDLength = 4 + 4 + 8; + ByteBuffer byteBufferMsgId = ByteBuffer.allocate(msgIDLength); + return MessageDecoder.createMessageId(byteBufferMsgId, + MessageExt.socketAddress2ByteBuffer(RemotingUtil.string2SocketAddress("127.0.0.1:10911")), + commitLogOffset); + } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java index 0d76652b97..8fe8c0d10a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java @@ -17,23 +17,24 @@ package org.apache.rocketmq.proxy.processor; -import java.util.Random; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.EndTransactionRequestData; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; public class TransactionProcessorTest extends BaseProcessorTest { - private Random random = new Random(); private static final String PRODUCER_GROUP = "producerGroup"; private TransactionProcessor transactionProcessor; @@ -51,18 +52,14 @@ public class TransactionProcessorTest extends BaseProcessorTest { } protected void testEndTransaction(int sysFlag, TransactionStatus transactionStatus) throws Throwable { - ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(EndTransactionRequestHeader.class); - doNothing().when(this.messageService).endTransactionOneway(any(), any(), requestHeaderArgumentCaptor.capture(), anyLong()); + doNothing().when(this.messageService).endTransactionOneway(any(), any(), any(), anyLong()); + ArgumentCaptor commitOrRollbackCaptor = ArgumentCaptor.forClass(Integer.class); + when(transactionService.genEndTransactionRequestHeader(anyString(), commitOrRollbackCaptor.capture(), anyBoolean(), anyString(), anyString())) + .thenReturn(new EndTransactionRequestData("brokerName", new EndTransactionRequestHeader())); - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - "brokerName", - "orgTxId", - random.nextLong(), - random.nextLong() - ); this.transactionProcessor.endTransaction( createContext(), - transactionId, + "transactionId", "msgId", PRODUCER_GROUP, transactionStatus, @@ -70,11 +67,7 @@ public class TransactionProcessorTest extends BaseProcessorTest { 3000 ); - EndTransactionRequestHeader requestHeader = requestHeaderArgumentCaptor.getValue(); - assertEquals(sysFlag, requestHeader.getCommitOrRollback().intValue()); - assertEquals(transactionId.getBrokerTransactionId(), requestHeader.getTransactionId()); - assertEquals(transactionId.getCommitLogOffset(), requestHeader.getCommitLogOffset().longValue()); - assertEquals(transactionId.getTranStateTableOffset(), requestHeader.getTranStateTableOffset().longValue()); + assertEquals(sysFlag, commitOrRollbackCaptor.getValue().intValue()); reset(this.messageService); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java index 52a71be530..5f18188e5d 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/LocalProxyRelayServiceTest.java @@ -28,6 +28,7 @@ import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRe import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext; +import org.apache.rocketmq.proxy.service.transaction.TransactionService; import org.apache.rocketmq.remoting.netty.NettyRemotingServer; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Before; @@ -46,11 +47,13 @@ public class LocalProxyRelayServiceTest { @Mock private BrokerController brokerControllerMock; @Mock + private TransactionService transactionService; + @Mock private NettyRemotingServer nettyRemotingServerMock; @Before public void setUp() { - localProxyRelayService = new LocalProxyRelayService(brokerControllerMock); + localProxyRelayService = new LocalProxyRelayService(brokerControllerMock, transactionService); Mockito.when(brokerControllerMock.getRemotingServer()).thenReturn(nettyRemotingServerMock); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java index fadb280e37..167abbe711 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/relay/ProxyChannelTest.java @@ -30,7 +30,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.common.protocol.header.ConsumeMessageDirectlyResultRequestHeader; import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestHeader; -import org.apache.rocketmq.proxy.service.transaction.TransactionId; +import org.apache.rocketmq.proxy.service.transaction.TransactionData; import org.apache.rocketmq.remoting.common.RemotingUtil; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Test; @@ -43,6 +43,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) @@ -71,6 +72,9 @@ public class ProxyChannelTest { @Test public void testWriteAndFlush() throws Exception { + when(this.proxyRelayService.processCheckTransactionState(any(), any(), any(), any())) + .thenReturn(new RelayData<>(mock(TransactionData.class), new CompletableFuture<>())); + ArgumentCaptor consumeMessageDirectlyArgumentCaptor = ArgumentCaptor.forClass(ConsumeMessageDirectlyResultRequestHeader.class); when(this.proxyRelayService.processConsumeMessageDirectly(any(), any(), consumeMessageDirectlyArgumentCaptor.capture())) @@ -82,7 +86,6 @@ public class ProxyChannelTest { .thenReturn(new CompletableFuture<>()); CheckTransactionStateRequestHeader checkTransactionStateRequestHeader = new CheckTransactionStateRequestHeader(); - checkTransactionStateRequestHeader.setBrokerName("broker"); checkTransactionStateRequestHeader.setTransactionId(MessageClientIDSetter.createUniqID()); RemotingCommand checkTransactionRequest = RemotingCommand.createRequestCommand(RequestCode.CHECK_TRANSACTION_STATE, checkTransactionStateRequestHeader); MessageExt transactionMessageExt = new MessageExt(); @@ -120,7 +123,7 @@ public class ProxyChannelTest { @Override protected CompletableFuture processCheckTransaction(CheckTransactionStateRequestHeader header, - MessageExt messageExt, TransactionId transactionId) { + MessageExt messageExt, TransactionData transactionData, CompletableFuture> responseFuture) { assertEquals(checkTransactionStateRequestHeader, header); assertArrayEquals(transactionMessageExt.getBody(), messageExt.getBody()); return CompletableFuture.completedFuture(null); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java new file mode 100644 index 0000000000..fa32839ee0 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java @@ -0,0 +1,135 @@ +/* + * 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.service.transaction; + +import java.util.List; +import java.util.Random; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class AbstractTransactionServiceTest extends InitConfigAndLoggerTest { + + private static final String BROKER_NAME = "mockBorker"; + private static final Random RANDOM = new Random(); + + public static class MockAbstractTransactionServiceTest extends AbstractTransactionService { + + @Override + protected String getBrokerNameByAddr(String brokerAddr) { + return BROKER_NAME; + } + + @Override + public void addTransactionSubscription(String group, List topicList) { + + } + + @Override + public void addTransactionSubscription(String group, String topic) { + + } + + @Override + public void replaceTransactionSubscription(String group, List topicList) { + + } + + @Override + public void unSubscribeAllTransactionTopic(String group) { + + } + } + + private TransactionService transactionService; + + @Before + public void before() throws Throwable { + super.before(); + this.transactionService = new MockAbstractTransactionServiceTest(); + } + + @Test + public void testAddAndGenEndHeader() { + Message message = new Message(); + message.putUserProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, "30"); + String txId = MessageClientIDSetter.createUniqID(); + + TransactionData transactionData = transactionService.addTransactionDataByBrokerName( + BROKER_NAME, + RANDOM.nextLong(), + RANDOM.nextLong(), + txId, + message + ); + assertNotNull(transactionData); + + EndTransactionRequestData requestData = transactionService.genEndTransactionRequestHeader( + "group", + MessageSysFlag.TRANSACTION_COMMIT_TYPE, + true, + txId, + txId + ); + + assertEquals(BROKER_NAME, requestData.getBrokerName()); + assertEquals(BROKER_NAME, transactionData.getBrokerName()); + assertEquals(transactionData.getCommitLogOffset(), requestData.getRequestHeader().getCommitLogOffset().longValue()); + assertEquals(transactionData.getTranStateTableOffset(), requestData.getRequestHeader().getTranStateTableOffset().longValue()); + + assertNull(transactionService.genEndTransactionRequestHeader( + "group", + MessageSysFlag.TRANSACTION_COMMIT_TYPE, + true, + txId, + txId + )); + } + + @Test + public void testOnSendCheckTransactionStateFailedFailed() { + Message message = new Message(); + message.putUserProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, "30"); + String txId = MessageClientIDSetter.createUniqID(); + + TransactionData transactionData = transactionService.addTransactionDataByBrokerName( + BROKER_NAME, + RANDOM.nextLong(), + RANDOM.nextLong(), + txId, + message + ); + transactionService.onSendCheckTransactionStateFailed(ProxyContext.createForInner(this.getClass()), transactionData); + assertNull(transactionService.genEndTransactionRequestHeader( + "group", + MessageSysFlag.TRANSACTION_COMMIT_TYPE, + true, + txId, + txId + )); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java new file mode 100644 index 0000000000..145226d4b7 --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.rocketmq.proxy.service.transaction; + +import java.time.Duration; +import java.util.Random; +import org.apache.commons.lang3.time.StopWatch; +import org.apache.rocketmq.common.message.MessageClientIDSetter; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +public class TransactionDataManagerTest extends InitConfigAndLoggerTest { + + private static final Random RANDOM = new Random(); + private TransactionDataManager transactionDataManager; + + @Before + public void before() throws Throwable { + super.before(); + this.transactionDataManager = new TransactionDataManager(); + } + + @After + public void after() { + super.after(); + } + + @Test + public void testAddAndRemove() { + TransactionData transactionData1 = createTransactionData(); + TransactionData transactionData2 = createTransactionData(transactionData1.getTransactionId()); + this.transactionDataManager.addTransactionData(transactionData1.getTransactionId(), transactionData1); + this.transactionDataManager.addTransactionData(transactionData1.getTransactionId(), transactionData2); + + assertEquals(1, this.transactionDataManager.transactionIdDataMap.size()); + assertEquals(2, this.transactionDataManager.transactionIdDataMap.get(transactionData1.getTransactionId()).size()); + + this.transactionDataManager.removeTransactionData(transactionData1.getTransactionId(), transactionData1); + assertEquals(1, this.transactionDataManager.transactionIdDataMap.size()); + this.transactionDataManager.removeTransactionData(transactionData1.getTransactionId(), transactionData2); + assertEquals(0, this.transactionDataManager.transactionIdDataMap.size()); + } + + @Test + public void testPollFirst() { + String txId = MessageClientIDSetter.createUniqID(); + TransactionData transactionData1 = createTransactionData(txId, System.currentTimeMillis() - Duration.ofMinutes(2).toMillis()); + TransactionData transactionData2 = createTransactionData(txId); + + this.transactionDataManager.addTransactionData(txId, transactionData1); + this.transactionDataManager.addTransactionData(txId, transactionData2); + + TransactionData resTransactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(txId); + assertSame(transactionData2, resTransactionData); + assertTrue(this.transactionDataManager.transactionIdDataMap.isEmpty()); + } + + @Test + public void testCleanExpire() { + String txId = MessageClientIDSetter.createUniqID(); + this.transactionDataManager.addTransactionData(txId, + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(100).toMillis())); + this.transactionDataManager.addTransactionData(txId, + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(500).toMillis())); + + this.transactionDataManager.addTransactionData(MessageClientIDSetter.createUniqID(), + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(1000).toMillis())); + + await().atMost(Duration.ofSeconds(2)).until(() -> { + this.transactionDataManager.cleanExpireTransactionData(); + return this.transactionDataManager.transactionIdDataMap.isEmpty(); + }); + } + + @Test + public void testWaitTransactionDataClear() throws InterruptedException { + String txId = MessageClientIDSetter.createUniqID(); + this.transactionDataManager.addTransactionData(txId, + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(100).toMillis())); + this.transactionDataManager.addTransactionData(txId, + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(500).toMillis())); + + this.transactionDataManager.addTransactionData(MessageClientIDSetter.createUniqID(), + createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(1000).toMillis())); + + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + this.transactionDataManager.waitTransactionDataClear(); + stopWatch.stop(); + assertTrue(Math.abs(stopWatch.getTime() - 1000) <= 50); + } + + private static TransactionData createTransactionData() { + return createTransactionData(MessageClientIDSetter.createUniqID()); + } + + private static TransactionData createTransactionData(String txId) { + return createTransactionData(txId, System.currentTimeMillis()); + } + + private static TransactionData createTransactionData(String txId, long checkTimestamp) { + return createTransactionData(txId, checkTimestamp, Duration.ofMinutes(1).toMillis()); + } + + private static TransactionData createTransactionData(String txId, long checkTimestamp, long checkImmunityTime) { + return new TransactionData( + "brokerName", + RANDOM.nextLong(), + RANDOM.nextLong(), + txId, + checkTimestamp, + checkImmunityTime + ); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java deleted file mode 100644 index 9e1887918a..0000000000 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionIdTest.java +++ /dev/null @@ -1,69 +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.proxy.service.transaction; - -import java.net.UnknownHostException; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class TransactionIdTest { - - private static final String BROKER_NAME = "brokerName"; - - @Test - public void test() throws UnknownHostException { - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - BROKER_NAME, - "71F99B78B6E261357FA259CCA6456118", 1234, 5678); - - TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); - - assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); - assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); - assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); - } - - @Test - public void testEmptyTransactionId() throws UnknownHostException { - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - BROKER_NAME, - "", 1234, 5678); - - TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); - - assertEquals(transactionId.getBrokerTransactionId(), decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); - assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); - assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); - } - - @Test - public void testNullTransactionId() throws UnknownHostException { - TransactionId transactionId = TransactionId.genByBrokerTransactionId( - BROKER_NAME, - null, 1234, 5678); - - TransactionId decodeTransactionId = TransactionId.decode(transactionId.getProxyTransactionId()); - - assertEquals("", decodeTransactionId.getBrokerTransactionId()); - assertEquals(transactionId.getBrokerName(), decodeTransactionId.getBrokerName()); - assertEquals(transactionId.getCommitLogOffset(), decodeTransactionId.getCommitLogOffset()); - assertEquals(transactionId.getTranStateTableOffset(), decodeTransactionId.getTranStateTableOffset()); - } -} \ No newline at end of file From eb380d9b4f9ef37c91514f97ea7d468762ca5108 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 27 Jun 2022 21:09:29 +0800 Subject: [PATCH 275/338] [ISSUE #3949] isolate transactionId by producerGroup --- .../proxy/processor/ProducerProcessor.java | 5 +-- .../relay/AbstractProxyRelayService.java | 5 ++- .../AbstractTransactionService.java | 13 ++++---- .../transaction/TransactionDataManager.java | 18 ++++++----- .../transaction/TransactionService.java | 6 ++-- .../processor/ProducerProcessorTest.java | 2 ++ .../AbstractTransactionServiceTest.java | 11 ++++--- .../TransactionDataManagerTest.java | 31 ++++++++++--------- 8 files changed, 53 insertions(+), 38 deletions(-) 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 9362580887..80ac2f4f6e 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 @@ -97,7 +97,7 @@ public class ProducerProcessor extends AbstractProcessor { if (SendStatus.SEND_OK.equals(sendResult.getSendStatus()) && tranType == MessageSysFlag.TRANSACTION_PREPARED_TYPE && StringUtils.isNotBlank(sendResult.getTransactionId())) { - fillTransactionData(messageQueue, sendResult, messageList); + fillTransactionData(producerGroup, messageQueue, sendResult, messageList); } } return sendResultList; @@ -108,7 +108,7 @@ public class ProducerProcessor extends AbstractProcessor { return FutureUtils.addExecutor(future, this.executor); } - protected void fillTransactionData(AddressableMessageQueue messageQueue, SendResult sendResult, List messageList) { + protected void fillTransactionData(String producerGroup, AddressableMessageQueue messageQueue, SendResult sendResult, List messageList) { try { MessageId id; if (sendResult.getOffsetMsgId() != null) { @@ -118,6 +118,7 @@ public class ProducerProcessor extends AbstractProcessor { } this.serviceManager.getTransactionService().addTransactionDataByBrokerName( messageQueue.getBrokerName(), + producerGroup, sendResult.getQueueOffset(), id.getOffset(), sendResult.getTransactionId(), diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java index 5b919681a5..27a9c36edf 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/AbstractProxyRelayService.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.service.relay; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -40,8 +41,10 @@ public abstract class AbstractProxyRelayService implements ProxyRelayService { public RelayData processCheckTransactionState(ProxyContext context, RemotingCommand command, CheckTransactionStateRequestHeader header, MessageExt messageExt) { CompletableFuture> future = new CompletableFuture<>(); + String group = messageExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP); TransactionData transactionData = transactionService.addTransactionDataByBrokerAddr( command.getExtFields().get(ProxyUtils.BROKER_ADDR), + group, header.getTranStateTableOffset(), header.getCommitLogOffset(), header.getTransactionId(), @@ -51,7 +54,7 @@ public abstract class AbstractProxyRelayService implements ProxyRelayService { String.format("add transaction data failed. request:%s, message:%s", command, messageExt)); } future.exceptionally(throwable -> { - this.transactionService.onSendCheckTransactionStateFailed(context, transactionData); + this.transactionService.onSendCheckTransactionStateFailed(context, group, transactionData); return null; }); return new RelayData<>(transactionData, future); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java index 5075ac0fda..504cbb6134 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java @@ -31,13 +31,13 @@ public abstract class AbstractTransactionService implements TransactionService, protected TransactionDataManager transactionDataManager = new TransactionDataManager(); @Override - public TransactionData addTransactionDataByBrokerAddr(String brokerAddr, long tranStateTableOffset, long commitLogOffset, String transactionId, + public TransactionData addTransactionDataByBrokerAddr(String brokerAddr, String producerGroup, long tranStateTableOffset, long commitLogOffset, String transactionId, Message message) { - return this.addTransactionDataByBrokerName(this.getBrokerNameByAddr(brokerAddr), tranStateTableOffset, commitLogOffset, transactionId, message); + return this.addTransactionDataByBrokerName(this.getBrokerNameByAddr(brokerAddr), producerGroup, tranStateTableOffset, commitLogOffset, transactionId, message); } @Override - public TransactionData addTransactionDataByBrokerName(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, + public TransactionData addTransactionDataByBrokerName(String brokerName, String producerGroup, long tranStateTableOffset, long commitLogOffset, String transactionId, Message message) { if (StringUtils.isBlank(brokerName)) { return null; @@ -49,6 +49,7 @@ public abstract class AbstractTransactionService implements TransactionService, System.currentTimeMillis(), checkImmunityTime); this.transactionDataManager.addTransactionData( + producerGroup, transactionId, transactionData ); @@ -58,7 +59,7 @@ public abstract class AbstractTransactionService implements TransactionService, @Override public EndTransactionRequestData genEndTransactionRequestHeader(String producerGroup, Integer commitOrRollback, boolean fromTransactionCheck, String msgId, String transactionId) { - TransactionData transactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(transactionId); + TransactionData transactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(producerGroup, transactionId); if (transactionData == null) { return null; } @@ -74,8 +75,8 @@ public abstract class AbstractTransactionService implements TransactionService, } @Override - public void onSendCheckTransactionStateFailed(ProxyContext context, TransactionData transactionData) { - this.transactionDataManager.removeTransactionData(transactionData.getTransactionId(), transactionData); + public void onSendCheckTransactionStateFailed(ProxyContext context, String producerGroup, TransactionData transactionData) { + this.transactionDataManager.removeTransactionData(producerGroup, transactionData.getTransactionId(), transactionData); } protected long parseCheckImmunityTime(Message message) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java index 5b883f3dd0..594ca5bc11 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java @@ -38,11 +38,15 @@ public class TransactionDataManager implements StartAndShutdown { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final AtomicLong maxTransactionDataExpireTime = new AtomicLong(System.currentTimeMillis()); - protected final Map> transactionIdDataMap = new ConcurrentHashMap<>(); + protected final Map> transactionIdDataMap = new ConcurrentHashMap<>(); protected final TransactionDataCleaner transactionDataCleaner = new TransactionDataCleaner(); - public void addTransactionData(String transactionId, TransactionData transactionData) { - this.transactionIdDataMap.compute(transactionId, (transactionIdKey, dataSet) -> { + protected String buildKey(String producerGroup, String transactionId) { + return producerGroup + "@" + transactionId; + } + + public void addTransactionData(String producerGroup, String transactionId, TransactionData transactionData) { + this.transactionIdDataMap.compute(buildKey(producerGroup, transactionId), (key, dataSet) -> { if (dataSet == null) { dataSet = new ConcurrentSkipListSet<>(); } @@ -51,10 +55,10 @@ public class TransactionDataManager implements StartAndShutdown { }); } - public TransactionData pollFirstNoExpireTransactionData(String transactionId) { + public TransactionData pollFirstNoExpireTransactionData(String producerGroup, String transactionId) { AtomicReference res = new AtomicReference<>(); long currTimestamp = System.currentTimeMillis(); - this.transactionIdDataMap.computeIfPresent(transactionId, (transactionIdKey, dataSet) -> { + this.transactionIdDataMap.computeIfPresent(buildKey(producerGroup, transactionId), (key, dataSet) -> { TransactionData data = dataSet.pollFirst(); while (data != null && data.getExpireTime() < currTimestamp) { data = dataSet.pollFirst(); @@ -70,8 +74,8 @@ public class TransactionDataManager implements StartAndShutdown { return res.get(); } - public void removeTransactionData(String transactionId, TransactionData transactionData) { - this.transactionIdDataMap.computeIfPresent(transactionId, (transactionIdKey, dataSet) -> { + public void removeTransactionData(String producerGroup, String transactionId, TransactionData transactionData) { + this.transactionIdDataMap.computeIfPresent(buildKey(producerGroup, transactionId), (key, dataSet) -> { dataSet.remove(transactionData); if (dataSet.isEmpty()) { return null; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java index 8be2391f3d..2a851051eb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionService.java @@ -30,14 +30,14 @@ public interface TransactionService { void unSubscribeAllTransactionTopic(String group); - TransactionData addTransactionDataByBrokerAddr(String brokerAddr, long tranStateTableOffset, long commitLogOffset, String transactionId, + TransactionData addTransactionDataByBrokerAddr(String brokerAddr, String producerGroup, long tranStateTableOffset, long commitLogOffset, String transactionId, Message message); - TransactionData addTransactionDataByBrokerName(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, + TransactionData addTransactionDataByBrokerName(String brokerName, String producerGroup, long tranStateTableOffset, long commitLogOffset, String transactionId, Message message); EndTransactionRequestData genEndTransactionRequestHeader(String producerGroup, Integer commitOrRollback, boolean fromTransactionCheck, String msgId, String transactionId); - void onSendCheckTransactionStateFailed(ProxyContext context, TransactionData transactionData); + void onSendCheckTransactionStateFailed(ProxyContext context, String producerGroup, TransactionData transactionData); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index ec6c8845b6..6a1972c197 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -98,6 +98,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { ArgumentCaptor commitLogOffsetCaptor = ArgumentCaptor.forClass(Long.class); when(transactionService.addTransactionDataByBrokerName( brokerNameCaptor.capture(), + anyString(), tranStateTableOffsetCaptor.capture(), commitLogOffsetCaptor.capture(), anyString(), any())).thenReturn(mock(TransactionData.class)); @@ -151,6 +152,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { ArgumentCaptor commitLogOffsetCaptor = ArgumentCaptor.forClass(Long.class); when(transactionService.addTransactionDataByBrokerName( brokerNameCaptor.capture(), + anyString(), tranStateTableOffsetCaptor.capture(), commitLogOffsetCaptor.capture(), anyString(), any())).thenReturn(mock(TransactionData.class)); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java index fa32839ee0..055ab0c0f0 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionServiceTest.java @@ -34,7 +34,8 @@ import static org.junit.Assert.assertNull; public class AbstractTransactionServiceTest extends InitConfigAndLoggerTest { - private static final String BROKER_NAME = "mockBorker"; + private static final String BROKER_NAME = "mockBroker"; + private static final String PRODUCER_GROUP = "producerGroup"; private static final Random RANDOM = new Random(); public static class MockAbstractTransactionServiceTest extends AbstractTransactionService { @@ -81,6 +82,7 @@ public class AbstractTransactionServiceTest extends InitConfigAndLoggerTest { TransactionData transactionData = transactionService.addTransactionDataByBrokerName( BROKER_NAME, + PRODUCER_GROUP, RANDOM.nextLong(), RANDOM.nextLong(), txId, @@ -89,7 +91,7 @@ public class AbstractTransactionServiceTest extends InitConfigAndLoggerTest { assertNotNull(transactionData); EndTransactionRequestData requestData = transactionService.genEndTransactionRequestHeader( - "group", + PRODUCER_GROUP, MessageSysFlag.TRANSACTION_COMMIT_TYPE, true, txId, @@ -118,14 +120,15 @@ public class AbstractTransactionServiceTest extends InitConfigAndLoggerTest { TransactionData transactionData = transactionService.addTransactionDataByBrokerName( BROKER_NAME, + PRODUCER_GROUP, RANDOM.nextLong(), RANDOM.nextLong(), txId, message ); - transactionService.onSendCheckTransactionStateFailed(ProxyContext.createForInner(this.getClass()), transactionData); + transactionService.onSendCheckTransactionStateFailed(ProxyContext.createForInner(this.getClass()), PRODUCER_GROUP, transactionData); assertNull(transactionService.genEndTransactionRequestHeader( - "group", + PRODUCER_GROUP, MessageSysFlag.TRANSACTION_COMMIT_TYPE, true, txId, diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java index 145226d4b7..2d03ab6af4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManagerTest.java @@ -32,7 +32,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; public class TransactionDataManagerTest extends InitConfigAndLoggerTest { - + private static final String PRODUCER_GROUP = "producerGroup"; private static final Random RANDOM = new Random(); private TransactionDataManager transactionDataManager; @@ -51,15 +51,16 @@ public class TransactionDataManagerTest extends InitConfigAndLoggerTest { public void testAddAndRemove() { TransactionData transactionData1 = createTransactionData(); TransactionData transactionData2 = createTransactionData(transactionData1.getTransactionId()); - this.transactionDataManager.addTransactionData(transactionData1.getTransactionId(), transactionData1); - this.transactionDataManager.addTransactionData(transactionData1.getTransactionId(), transactionData2); + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, transactionData1.getTransactionId(), transactionData1); + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, transactionData1.getTransactionId(), transactionData2); assertEquals(1, this.transactionDataManager.transactionIdDataMap.size()); - assertEquals(2, this.transactionDataManager.transactionIdDataMap.get(transactionData1.getTransactionId()).size()); + assertEquals(2, this.transactionDataManager.transactionIdDataMap.get( + transactionDataManager.buildKey(PRODUCER_GROUP, transactionData1.getTransactionId())).size()); - this.transactionDataManager.removeTransactionData(transactionData1.getTransactionId(), transactionData1); + this.transactionDataManager.removeTransactionData(PRODUCER_GROUP, transactionData1.getTransactionId(), transactionData1); assertEquals(1, this.transactionDataManager.transactionIdDataMap.size()); - this.transactionDataManager.removeTransactionData(transactionData1.getTransactionId(), transactionData2); + this.transactionDataManager.removeTransactionData(PRODUCER_GROUP, transactionData1.getTransactionId(), transactionData2); assertEquals(0, this.transactionDataManager.transactionIdDataMap.size()); } @@ -69,10 +70,10 @@ public class TransactionDataManagerTest extends InitConfigAndLoggerTest { TransactionData transactionData1 = createTransactionData(txId, System.currentTimeMillis() - Duration.ofMinutes(2).toMillis()); TransactionData transactionData2 = createTransactionData(txId); - this.transactionDataManager.addTransactionData(txId, transactionData1); - this.transactionDataManager.addTransactionData(txId, transactionData2); + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, transactionData1); + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, transactionData2); - TransactionData resTransactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(txId); + TransactionData resTransactionData = this.transactionDataManager.pollFirstNoExpireTransactionData(PRODUCER_GROUP, txId); assertSame(transactionData2, resTransactionData); assertTrue(this.transactionDataManager.transactionIdDataMap.isEmpty()); } @@ -80,12 +81,12 @@ public class TransactionDataManagerTest extends InitConfigAndLoggerTest { @Test public void testCleanExpire() { String txId = MessageClientIDSetter.createUniqID(); - this.transactionDataManager.addTransactionData(txId, + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(100).toMillis())); - this.transactionDataManager.addTransactionData(txId, + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(500).toMillis())); - this.transactionDataManager.addTransactionData(MessageClientIDSetter.createUniqID(), + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, MessageClientIDSetter.createUniqID(), createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(1000).toMillis())); await().atMost(Duration.ofSeconds(2)).until(() -> { @@ -97,12 +98,12 @@ public class TransactionDataManagerTest extends InitConfigAndLoggerTest { @Test public void testWaitTransactionDataClear() throws InterruptedException { String txId = MessageClientIDSetter.createUniqID(); - this.transactionDataManager.addTransactionData(txId, + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(100).toMillis())); - this.transactionDataManager.addTransactionData(txId, + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, txId, createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(500).toMillis())); - this.transactionDataManager.addTransactionData(MessageClientIDSetter.createUniqID(), + this.transactionDataManager.addTransactionData(PRODUCER_GROUP, MessageClientIDSetter.createUniqID(), createTransactionData(txId, System.currentTimeMillis(), Duration.ofMillis(1000).toMillis())); StopWatch stopWatch = new StopWatch(); From 49616206183a04992b9801972d4f0ba4faaab478 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 14:54:01 +0800 Subject: [PATCH 276/338] [ISSUE #3949] parameter validate --- .../client/exception/MQClientException.java | 7 + .../rocketmq/client/impl/MQClientAPIImpl.java | 17 +- .../proxy/common/ProxyExceptionCode.java | 9 +- .../proxy/common/utils/ExceptionUtils.java | 3 + .../rocketmq/proxy/config/ProxyConfig.java | 61 ++++ .../grpc/v2/AbstractMessingActivity.java | 76 ++++- .../grpc/v2/GrpcMessagingApplication.java | 244 ++++++++++------ .../proxy/grpc/v2/client/ClientActivity.java | 19 +- .../grpc/v2/common/GrpcProxyException.java | 4 +- .../proxy/grpc/v2/common/ResponseBuilder.java | 85 ++---- .../grpc/v2/consumer/AckMessageActivity.java | 20 +- .../ChangeInvisibleDurationActivity.java | 2 + .../v2/consumer/ReceiveMessageActivity.java | 2 + .../producer/ForwardMessageToDLQActivity.java | 1 + .../grpc/v2/producer/SendMessageActivity.java | 87 +++++- .../proxy/grpc/v2/route/RouteActivity.java | 11 +- .../transaction/EndTransactionActivity.java | 7 + .../proxy/processor/AbstractProcessor.java | 4 +- .../proxy/processor/ConsumerProcessor.java | 4 +- .../service/message/LocalMessageService.java | 2 +- .../service/message/LocalRemotingCommand.java | 2 + .../grpc/v2/AbstractMessingActivityTest.java | 77 +++++ .../grpc/v2/GrpcMessagingApplicationTest.java | 28 +- .../v2/consumer/AckMessageActivityTest.java | 8 +- .../v2/producer/SendMessageActivityTest.java | 272 ++++++++++++++++++ .../grpc/v2/route/RouteActivityTest.java | 24 +- .../message/LocalMessageServiceTest.java | 2 +- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 +- .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 2 +- 29 files changed, 864 insertions(+), 218 deletions(-) create mode 100644 proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java diff --git a/client/src/main/java/org/apache/rocketmq/client/exception/MQClientException.java b/client/src/main/java/org/apache/rocketmq/client/exception/MQClientException.java index f4534742d5..9bbcce2178 100644 --- a/client/src/main/java/org/apache/rocketmq/client/exception/MQClientException.java +++ b/client/src/main/java/org/apache/rocketmq/client/exception/MQClientException.java @@ -37,6 +37,13 @@ public class MQClientException extends Exception { this.errorMessage = errorMessage; } + public MQClientException(int responseCode, String errorMessage, Throwable cause) { + super(FAQUrl.attachDefaultURL("CODE: " + UtilAll.responseCode2String(responseCode) + " DESC: " + + errorMessage), cause); + this.responseCode = responseCode; + this.errorMessage = errorMessage; + } + public int getResponseCode() { return responseCode; } 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 33bd62b0f7..5d1d76c291 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 @@ -31,6 +31,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.ClientConfig; +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; @@ -863,9 +864,9 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { } } else { if (!responseFuture.isSendRequestOK()) { - popCallback.onException(new MQClientException("send request failed to " + addr + ". Request: " + request, responseFuture.getCause())); + 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("wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request, + 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())); @@ -902,9 +903,9 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { } } else { if (!responseFuture.isSendRequestOK()) { - ackCallback.onException(new MQClientException("send request failed to " + addr + ". Request: " + request, responseFuture.getCause())); + 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("wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request, + 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())); @@ -948,9 +949,9 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { } } else { if (!responseFuture.isSendRequestOK()) { - ackCallback.onException(new MQClientException("send request failed to " + addr + ". Request: " + request, responseFuture.getCause())); + 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("wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request, + 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: " + timeoutMillis + ". Request: " + request, responseFuture.getCause())); @@ -980,9 +981,9 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { } } else { if (!responseFuture.isSendRequestOK()) { - pullCallback.onException(new MQClientException("send request failed to " + addr + ". Request: " + request, responseFuture.getCause())); + 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("wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request, + 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())); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index b2a26d9a98..1fd501a41b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -17,12 +17,9 @@ package org.apache.rocketmq.proxy.common; public enum ProxyExceptionCode { - FORBIDDEN, - RECEIPT_HANDLE_EXPIRED, INVALID_BROKER_NAME, - INVALID_RECEIPT_HANDLE, - ILLEGAL_MESSAGE, - INTERNAL_SERVER_ERROR, + FORBIDDEN, MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, - NOT_IMPLEMENTED, + INVALID_RECEIPT_HANDLE, + INTERNAL_SERVER_ERROR, } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java index b4b9ad9189..e85360a5da 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/utils/ExceptionUtils.java @@ -31,6 +31,9 @@ public class ExceptionUtils { } public static String getErrorDetailMessage(Throwable t) { + if (t == null) { + return null; + } StringBuilder sb = new StringBuilder(); sb.append(t.getMessage()).append(". ").append(t.getClass().getSimpleName()); 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 84aececd30..eb7044a853 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 @@ -57,6 +57,27 @@ public class ProxyConfig { */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; + /** + * the regex to check topic name, empty string means not to check + */ + private String topicNameCheckRegex = "^[%a-zA-Z0-9_-]{1,127}$"; + /** + * the regex to check consumer group name, empty string means not to check + */ + private String consumerGroupNameCheckRegex = "^[%a-zA-Z0-9_-]{1,255}$"; + /** + * max message body size, 0 or negative number means no limit for proxy + */ + private int maxMessageSize = 4 * 1024 * 1024; + /** + * max user property size, 0 or negative number means no limit for proxy + */ + private int maxUserPropertySize = 16 * 1024; + /** + * max message group size, 0 or negative number means no limit for proxy + */ + private int maxMessageGroupSize = 1024; + private int channelExpiredInSeconds = 60; private int contextExpiredInSeconds = 30; @@ -267,6 +288,46 @@ public class ProxyConfig { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } + public String getTopicNameCheckRegex() { + return topicNameCheckRegex; + } + + public void setTopicNameCheckRegex(String topicNameCheckRegex) { + this.topicNameCheckRegex = topicNameCheckRegex; + } + + public String getConsumerGroupNameCheckRegex() { + return consumerGroupNameCheckRegex; + } + + public void setConsumerGroupNameCheckRegex(String consumerGroupNameCheckRegex) { + this.consumerGroupNameCheckRegex = consumerGroupNameCheckRegex; + } + + public int getMaxMessageSize() { + return maxMessageSize; + } + + public void setMaxMessageSize(int maxMessageSize) { + this.maxMessageSize = maxMessageSize; + } + + public int getMaxUserPropertySize() { + return maxUserPropertySize; + } + + public void setMaxUserPropertySize(int maxUserPropertySize) { + this.maxUserPropertySize = maxUserPropertySize; + } + + public int getMaxMessageGroupSize() { + return maxMessageGroupSize; + } + + public void setMaxMessageGroupSize(int maxMessageGroupSize) { + this.maxMessageGroupSize = maxMessageGroupSize; + } + public int getChannelExpiredInSeconds() { return channelExpiredInSeconds; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 2ea08b462d..0949cafdc9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -16,20 +16,94 @@ */ package org.apache.rocketmq.proxy.grpc.v2; +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Resource; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.topic.TopicValidator; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.config.ConfigurationManager; 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.GrpcProxyException; import org.apache.rocketmq.proxy.processor.MessagingProcessor; public abstract class AbstractMessingActivity { - + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); protected final MessagingProcessor messagingProcessor; protected final GrpcClientSettingsManager grpcClientSettingsManager; protected final GrpcChannelManager grpcChannelManager; + protected static final Map CHECK_PATTERN_CACHE = new ConcurrentHashMap<>(); + public AbstractMessingActivity(MessagingProcessor messagingProcessor, GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { this.messagingProcessor = messagingProcessor; this.grpcClientSettingsManager = grpcClientSettingsManager; this.grpcChannelManager = grpcChannelManager; } + + protected Pattern getPattern(String regex) { + return CHECK_PATTERN_CACHE.compute(regex, (regexKey, oldPattern) -> { + try { + return Pattern.compile(regex); + } catch (Exception e) { + log.error("create check pattern failed. regex:{}", regex, e); + return oldPattern; + } + }); + } + + protected void validateTopic(Resource topic) { + String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + if (StringUtils.isBlank(topicName)) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "topic name cannot be empty"); + } + if (TopicValidator.isSystemTopic(topicName)) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "cannot access system topic"); + } + String regex = ConfigurationManager.getProxyConfig().getTopicNameCheckRegex(); + if (StringUtils.isBlank(regex)) { + return; + } + Pattern pattern = getPattern(regex); + if (pattern == null) { + throw new GrpcProxyException(Code.INTERNAL_SERVER_ERROR, "get topic name check pattern failed"); + } + if (!pattern.matcher(topicName).matches()) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "the format of topic is not correct"); + } + } + + protected void validateConsumerGroup(Resource consumerGroup) { + String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); + if (StringUtils.isBlank(consumerGroupName)) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "consumer group cannot be empty"); + } + if (MixAll.isSysConsumerGroup(consumerGroupName)) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "cannot use system consumer group"); + } + String regex = ConfigurationManager.getProxyConfig().getConsumerGroupNameCheckRegex(); + if (StringUtils.isBlank(regex)) { + return; + } + Pattern pattern = getPattern(regex); + if (pattern == null) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "get consumer group check pattern failed"); + } + if (!pattern.matcher(consumerGroupName).matches()) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "the format of consumer group is not correct"); + } + } + + protected void validateTopicAndConsumerGroup(Resource topic, Resource consumerGroup) { + validateTopic(topic); + validateConsumerGroup(consumerGroup); + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 299abb31cb..f9f2760e1d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -57,6 +57,7 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseWriter; import org.apache.rocketmq.proxy.processor.MessagingProcessor; @@ -147,9 +148,8 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ } protected void addExecutor(ExecutorService executor, ProxyContext context, V request, Runnable runnable, - StreamObserver responseObserver, - T executeRejectResponse) { - executor.submit(new GrpcTask<>(runnable, context, request, responseObserver, executeRejectResponse)); + StreamObserver responseObserver, Function statusResponseCreator) { + executor.submit(new GrpcTask<>(runnable, context, request, responseObserver, statusResponseCreator.apply(flowLimitStatus()))); } protected void writeResponse(ProxyContext context, V request, T response, StreamObserver responseObserver, @@ -179,159 +179,218 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ return context; } + protected void validateContext(ProxyContext context) { + if (StringUtils.isBlank(context.getClientID())) { + throw new GrpcProxyException(Code.BAD_REQUEST_CLIENT_ID, "client id cannot be empty"); + } + } + protected String getDefaultStringMetadataInfo(Metadata headers, Metadata.Key key) { return StringUtils.defaultString(headers.get(key)); } @Override public void queryRoute(QueryRouteRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> QueryRouteResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.routeThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.queryRoute(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> QueryRouteResponse.newBuilder().setStatus(status).build())), - responseObserver, - QueryRouteResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.routeThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.queryRoute(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void heartbeat(HeartbeatRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> HeartbeatResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.clientManagerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.heartbeat(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> HeartbeatResponse.newBuilder().setStatus(status).build())), - responseObserver, - HeartbeatResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.clientManagerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.heartbeat(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void sendMessage(SendMessageRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> SendMessageResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.producerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.sendMessage(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> SendMessageResponse.newBuilder().setStatus(status).build())), - responseObserver, - SendMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.producerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.sendMessage(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void queryAssignment(QueryAssignmentRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> QueryAssignmentResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.routeThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.queryAssignment(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> QueryAssignmentResponse.newBuilder().setStatus(status).build())), - responseObserver, - QueryAssignmentResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.routeThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.queryAssignment(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void receiveMessage(ReceiveMessageRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> ReceiveMessageResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.consumerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.receiveMessage(context, request, responseObserver), - responseObserver, - ReceiveMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); - + try { + validateContext(context); + this.addExecutor(this.consumerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.receiveMessage(context, request, responseObserver), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void ackMessage(AckMessageRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> AckMessageResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.consumerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.ackMessage(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> AckMessageResponse.newBuilder().setStatus(status).build())), - responseObserver, - AckMessageResponse.newBuilder().setStatus(flowLimitStatus()).build()); - + try { + validateContext(context); + this.addExecutor(this.consumerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.ackMessage(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void forwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.producerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.forwardMessageToDeadLetterQueue(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(status).build())), - responseObserver, - ForwardMessageToDeadLetterQueueResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.producerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.forwardMessageToDeadLetterQueue(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void endTransaction(EndTransactionRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> EndTransactionResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.transactionThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.endTransaction(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> EndTransactionResponse.newBuilder().setStatus(status).build())), - responseObserver, - EndTransactionResponse.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + this.addExecutor(this.transactionThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.endTransaction(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void notifyClientTermination(NotifyClientTerminationRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> NotifyClientTerminationResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.clientManagerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.notifyClientTermination(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> NotifyClientTerminationResponse.newBuilder().setStatus(status).build())), - responseObserver, - NotifyClientTerminationResponse.newBuilder().setStatus(flowLimitStatus()).build()); - + try { + validateContext(context); + this.addExecutor(this.clientManagerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.notifyClientTermination(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public void changeInvisibleDuration(ChangeInvisibleDurationRequest request, StreamObserver responseObserver) { + Function statusResponseCreator = status -> ChangeInvisibleDurationResponse.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); - this.addExecutor(this.consumerThreadPoolExecutor, - context, - request, - () -> grpcMessingActivity.changeInvisibleDuration(context, request) - .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, - status -> ChangeInvisibleDurationResponse.newBuilder().setStatus(status).build())), - responseObserver, - ChangeInvisibleDurationResponse.newBuilder().setStatus(flowLimitStatus()).build()); - + try { + validateContext(context); + this.addExecutor(this.consumerThreadPoolExecutor, + context, + request, + () -> grpcMessingActivity.changeInvisibleDuration(context, request) + .whenComplete((response, throwable) -> writeResponse(context, request, response, responseObserver, throwable, statusResponseCreator)), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, request, null, responseObserver, t, statusResponseCreator); + } } @Override public StreamObserver telemetry(StreamObserver responseObserver) { + Function statusResponseCreator = status -> TelemetryCommand.newBuilder().setStatus(status).build(); ProxyContext context = createContext(); StreamObserver responseTelemetryCommand = grpcMessingActivity.telemetry(context, responseObserver); return new StreamObserver() { @Override public void onNext(TelemetryCommand value) { - addExecutor(clientManagerThreadPoolExecutor, - context, - value, - () -> responseTelemetryCommand.onNext(value), - responseObserver, - TelemetryCommand.newBuilder().setStatus(flowLimitStatus()).build()); + try { + validateContext(context); + addExecutor(clientManagerThreadPoolExecutor, + context, + value, + () -> responseTelemetryCommand.onNext(value), + responseObserver, + statusResponseCreator); + } catch (Throwable t) { + writeResponse(context, value, null, responseObserver, t, statusResponseCreator); + } } @Override @@ -371,7 +430,8 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected final T executeRejectResponse; protected final StreamObserver streamObserver; - public GrpcTask(Runnable runnable, ProxyContext context, V request, StreamObserver streamObserver, T executeRejectResponse) { + public GrpcTask(Runnable runnable, ProxyContext context, V request, StreamObserver streamObserver, + T executeRejectResponse) { this.runnable = runnable; this.context = context; this.streamObserver = streamObserver; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 966c0583c1..08f251096c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -105,6 +105,7 @@ public class ClientActivity extends AbstractMessingActivity { switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { + validateTopic(topic); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -116,9 +117,7 @@ public class ClientActivity extends AbstractMessingActivity { } case PUSH_CONSUMER: case SIMPLE_CONSUMER: { - if (!request.hasGroup()) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); - } + validateConsumerGroup(request.getGroup()); String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -174,9 +173,7 @@ public class ClientActivity extends AbstractMessingActivity { break; case PUSH_CONSUMER: case SIMPLE_CONSUMER: - if (!request.hasGroup()) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "group cannot be empty for consumer"); - } + validateConsumerGroup(request.getGroup()); String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); GrpcClientChannel channel = this.grpcChannelManager.removeChannel(consumerGroup, clientId); if (channel != null) { @@ -219,10 +216,8 @@ public class ClientActivity extends AbstractMessingActivity { break; } } - } catch (Exception e) { - responseObserver.onNext(TelemetryCommand.newBuilder() - .setStatus(ResponseBuilder.buildStatus(e)) - .build()); + } catch (Throwable t) { + responseObserver.onNext(convertToTelemetryCommand(t)); } } @@ -238,6 +233,10 @@ public class ClientActivity extends AbstractMessingActivity { }; } + protected TelemetryCommand convertToTelemetryCommand(Throwable t) { + return TelemetryCommand.newBuilder().setStatus(ResponseBuilder.buildStatus(t)).build(); + } + protected TelemetryCommand processClientSettings(ProxyContext ctx, TelemetryCommand request, StreamObserver responseObserver) { String clientId = ctx.getClientID(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index f89639dc58..0d055afcea 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -30,11 +30,9 @@ public class GrpcProxyException extends RuntimeException { private static final Map CODE_MAPPING = new HashMap<>(); static { - CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.INVALID_RECEIPT_HANDLE); + CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.BAD_REQUEST); CODE_MAPPING.put(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, Code.INVALID_RECEIPT_HANDLE); - CODE_MAPPING.put(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, Code.RECEIPT_HANDLE_EXPIRED); CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); - CODE_MAPPING.put(ProxyExceptionCode.ILLEGAL_MESSAGE, Code.ILLEGAL_MESSAGE); CODE_MAPPING.put(ProxyExceptionCode.INTERNAL_SERVER_ERROR, Code.INTERNAL_SERVER_ERROR); CODE_MAPPING.put(ProxyExceptionCode.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, Code.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java index 412b01d34b..799e9c4185 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java @@ -19,16 +19,32 @@ package org.apache.rocketmq.proxy.grpc.v2.common; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Status; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.rocketmq.client.common.ClientErrorCode; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.utils.ExceptionUtils; +import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; public class ResponseBuilder { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + public static final Map RESPONSE_CODE_MAPPING = new ConcurrentHashMap<>(); + + static { + RESPONSE_CODE_MAPPING.put(ResponseCode.SUCCESS, Code.OK); + RESPONSE_CODE_MAPPING.put(ResponseCode.SYSTEM_BUSY, Code.TOO_MANY_REQUESTS); + RESPONSE_CODE_MAPPING.put(ResponseCode.REQUEST_CODE_NOT_SUPPORTED, Code.NOT_IMPLEMENTED); + RESPONSE_CODE_MAPPING.put(ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST, Code.CONSUMER_GROUP_NOT_FOUND); + RESPONSE_CODE_MAPPING.put(ClientErrorCode.ACCESS_BROKER_TIMEOUT, Code.PROXY_TIMEOUT); + } public static Status buildStatus(Throwable t) { t = ExceptionUtils.getRealException(t); @@ -40,6 +56,20 @@ public class ResponseBuilder { GrpcProxyException grpcProxyException = (GrpcProxyException) t; return ResponseBuilder.buildStatus(grpcProxyException.getCode(), grpcProxyException.getMessage()); } + if (TopicRouteHelper.isTopicNotExistError(t)) { + return ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage()); + } + if (t instanceof MQBrokerException) { + MQBrokerException mqBrokerException = (MQBrokerException) t; + return ResponseBuilder.buildStatus(buildCode(mqBrokerException.getResponseCode()), mqBrokerException.getErrorMessage()); + } + if (t instanceof MQClientException) { + MQClientException mqClientException = (MQClientException) t; + return ResponseBuilder.buildStatus(buildCode(mqClientException.getResponseCode()), mqClientException.getErrorMessage()); + } + if (t instanceof RemotingTimeoutException) { + return ResponseBuilder.buildStatus(Code.PROXY_TIMEOUT, t.getMessage()); + } log.error("internal server error", t); return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, ExceptionUtils.getErrorDetailMessage(t)); @@ -64,59 +94,6 @@ public class ResponseBuilder { } public static Code buildCode(int remotingResponseCode) { - switch (remotingResponseCode) { - case ResponseCode.SUCCESS: - case ResponseCode.NO_MESSAGE: - case ResponseCode.PULL_RETRY_IMMEDIATELY: { - return Code.OK; - } - case ResponseCode.SYSTEM_BUSY: - case ResponseCode.POLLING_FULL: { - return Code.TOO_MANY_REQUESTS; - } - case ResponseCode.REQUEST_CODE_NOT_SUPPORTED: { - return Code.UNRECOGNIZED; - } - case ResponseCode.MESSAGE_ILLEGAL: { - return Code.ILLEGAL_MESSAGE; - } - case ResponseCode.VERSION_NOT_SUPPORTED: { - return Code.VERSION_UNSUPPORTED; - } - case ResponseCode.SLAVE_NOT_AVAILABLE: { - return Code.HA_NOT_AVAILABLE; - } - case ResponseCode.PULL_OFFSET_MOVED: { - return Code.ILLEGAL_MESSAGE_OFFSET; - } - case ResponseCode.NO_PERMISSION: { - return Code.FORBIDDEN; - } - case ResponseCode.TOPIC_NOT_EXIST: { - return Code.TOPIC_NOT_FOUND; - } - case ResponseCode.PULL_NOT_FOUND: { - return Code.MESSAGE_NOT_FOUND; - } - case ResponseCode.FLUSH_DISK_TIMEOUT: { - return Code.MASTER_PERSISTENCE_TIMEOUT; - } - case ResponseCode.FLUSH_SLAVE_TIMEOUT: { - return Code.SLAVE_PERSISTENCE_TIMEOUT; - } - case ResponseCode.POLLING_TIMEOUT: { - return Code.GATEWAY_TIMEOUT; - } - default: { - return Code.INTERNAL_SERVER_ERROR; - } - } - } - - public static String buildMessage(int responseCode, String remark) { - if (remark != null) { - return "ResponseCode: " + responseCode + " " + remark; - } - return "ResponseCode: " + responseCode; + return RESPONSE_CODE_MAPPING.getOrDefault(remotingResponseCode, Code.INTERNAL_SERVER_ERROR); } } 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 6cd6a56565..2e19a2c329 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 @@ -52,6 +52,8 @@ public class AckMessageActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); 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)); @@ -90,10 +92,6 @@ public class AckMessageActivity extends AbstractMessingActivity { protected CompletableFuture processAckMessage(ProxyContext ctx, AckMessageRequest request, AckMessageEntry ackMessageEntry) { CompletableFuture future = new CompletableFuture<>(); - AckMessageResultEntry.Builder failResult = AckMessageResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message failed")) - .setMessageId(ackMessageEntry.getMessageId()) - .setReceiptHandle(ackMessageEntry.getReceiptHandle()); try { ReceiptHandle receiptHandle = ReceiptHandle.decode(ackMessageEntry.getReceiptHandle()); @@ -110,16 +108,24 @@ public class AckMessageActivity extends AbstractMessingActivity { receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle()); } future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); - }).exceptionally(throwable -> { - future.complete(failResult.setStatus(ResponseBuilder.buildStatus(throwable)).build()); + }).exceptionally(t -> { + future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, t)); return null; }); } catch (Throwable t) { - future.complete(failResult.setStatus(ResponseBuilder.buildStatus(t)).build()); + future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, t)); } return future; } + protected AckMessageResultEntry convertToAckMessageResultEntry(ProxyContext ctx, AckMessageEntry ackMessageEntry, Throwable throwable) { + return AckMessageResultEntry.newBuilder() + .setStatus(ResponseBuilder.buildStatus(throwable)) + .setMessageId(ackMessageEntry.getMessageId()) + .setReceiptHandle(ackMessageEntry.getReceiptHandle()) + .build(); + } + protected AckMessageResultEntry convertToAckMessageResultEntry(ProxyContext ctx, AckMessageEntry ackMessageEntry, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index 7c9a664b27..bfee5c3134 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -48,6 +48,8 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); try { + validateTopicAndConsumerGroup(request.getTopic(), request.getGroup()); + ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 490fcd57bc..db345d468d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -86,6 +86,8 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { actualInvisibleTime = Math.min(actualInvisibleTime, proxyConfig.getRenewSliceTimeMillis()); } + validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); FilterExpression filterExpression = request.getFilterExpression(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java index a8a0047c4b..ceb6dfbca2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -40,6 +40,7 @@ public class ForwardMessageToDLQActivity extends AbstractMessingActivity { ForwardMessageToDeadLetterQueueRequest request) { CompletableFuture future = new CompletableFuture<>(); try { + validateTopicAndConsumerGroup(request.getTopic(), request.getGroup()); ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); return this.messagingProcessor.forwardMessageToDeadLetterQueue( 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 da37513006..117fc7b007 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 @@ -25,6 +25,7 @@ import apache.rocketmq.v2.SendMessageResponse; import apache.rocketmq.v2.SendResultEntry; import com.google.common.collect.Maps; import com.google.common.hash.Hashing; +import com.google.protobuf.ByteString; import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; @@ -42,6 +43,7 @@ import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.sysflag.MessageSysFlag; 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; @@ -71,6 +73,8 @@ public class SendMessageActivity extends AbstractMessingActivity { List messageList = request.getMessagesList(); apache.rocketmq.v2.Message message = messageList.get(0); Resource topic = message.getTopic(); + validateTopic(topic); + future = this.messagingProcessor.sendMessage( ctx, new SendMessageQueueSelector(request), @@ -101,6 +105,7 @@ public class SendMessageActivity extends AbstractMessingActivity { protected Message buildMessage(apache.rocketmq.v2.Message protoMessage, String producerGroup) { String topicName = GrpcConverter.wrapResourceWithNamespace(protoMessage.getTopic()); + validateMessageBodySize(protoMessage.getBody()); Message messageExt = new Message(); messageExt.setTopic(topicName); messageExt.setBody(protoMessage.getBody().toByteArray()); @@ -125,33 +130,94 @@ public class SendMessageActivity extends AbstractMessingActivity { return sysFlag; } + protected void validateMessageBodySize(ByteString body) { + int max = ConfigurationManager.getProxyConfig().getMaxMessageSize(); + if (max <= 0) { + return; + } + if (body.size() > max) { + throw new GrpcProxyException(Code.MESSAGE_BODY_TOO_LARGE, "message body cannot exceed the max " + max); + } + } + + protected void validateTag(String tag) { + if (StringUtils.isNotEmpty(tag)) { + if (StringUtils.isBlank(tag)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot be the char sequence of whitespace"); + } + if (tag.contains("|")) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot contain '|'"); + } + } + } + + protected void validateMessageKey(String key) { + if (StringUtils.isNotEmpty(key)) { + if (StringUtils.isBlank(key)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_KEY, "key cannot be the char sequence of whitespace"); + } + } + } + + protected void validateMessageGroup(String messageGroup) { + if (StringUtils.isNotEmpty(messageGroup)) { + if (StringUtils.isBlank(messageGroup)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_GROUP, "message group cannot be the char sequence of whitespace"); + } + int maxSize = ConfigurationManager.getProxyConfig().getMaxMessageGroupSize(); + if (maxSize <= 0) { + return; + } + if (messageGroup.length() >= maxSize) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_GROUP, "message group exceed the max size " + maxSize); + } + } + } + + protected void validateMessagePropertySize(Map property) { + int maxSize = ConfigurationManager.getProxyConfig().getMaxUserPropertySize(); + if (maxSize <= 0) { + return; + } + int curSize = 0; + for (Map.Entry entry : property.entrySet()) { + curSize += entry.getKey().length(); + curSize += entry.getValue().length(); + if (curSize > maxSize) { + throw new GrpcProxyException(Code.MESSAGE_PROPERTIES_TOO_LARGE, "the size of message properties cannot exceed the max " + maxSize); + } + } + } + protected Map buildMessageProperty(apache.rocketmq.v2.Message message, String producerGroup) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties Map userProperties = message.getUserPropertiesMap(); - for (String key : userProperties.keySet()) { - if (MessageConst.STRING_HASH_SET.contains(key)) { - throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + key); + for (Map.Entry userPropertiesEntry : userProperties.entrySet()) { + if (MessageConst.STRING_HASH_SET.contains(userPropertiesEntry.getKey())) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + userPropertiesEntry.getKey()); } } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); // set tag String tag = message.getSystemProperties().getTag(); - if (!"".equals(tag)) { - messageWithHeader.setTags(tag); - } + validateTag(tag); + messageWithHeader.setTags(tag); // set keys List keysList = message.getSystemProperties().getKeysList(); + for (String key : keysList) { + validateMessageKey(key); + } if (keysList.size() > 0) { messageWithHeader.setKeys(keysList); } // set message id String messageId = message.getSystemProperties().getMessageId(); - if ("".equals(messageId)) { - throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_ID, "message id is empty"); + if (StringUtils.isBlank(messageId)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_ID, "message id cannot be empty"); } MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, messageId); @@ -180,7 +246,8 @@ public class SendMessageActivity extends AbstractMessingActivity { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_PRODUCER_GROUP, producerGroup); // set message group String messageGroup = message.getSystemProperties().getMessageGroup(); - if (!messageGroup.isEmpty()) { + if (StringUtils.isNotEmpty(messageGroup)) { + validateMessageGroup(messageGroup); MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_SHARDING_KEY, messageGroup); } // set trace context @@ -188,6 +255,8 @@ public class SendMessageActivity extends AbstractMessingActivity { if (!traceContext.isEmpty()) { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); } + + validateMessagePropertySize(messageWithHeader.getProperties()); return messageWithHeader.getProperties(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index 63f69b8e05..5967220456 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -47,7 +47,6 @@ import org.apache.rocketmq.proxy.grpc.v2.common.GrpcConverter; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.proxy.service.route.TopicRouteHelper; public class RouteActivity extends AbstractMessingActivity { @@ -59,6 +58,7 @@ public class RouteActivity extends AbstractMessingActivity { public CompletableFuture queryRoute(ProxyContext ctx, QueryRouteRequest request) { CompletableFuture future = new CompletableFuture<>(); try { + validateTopic(request.getTopic()); List addressList = this.convertToAddressList(request.getEndpoints()); ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( @@ -86,13 +86,7 @@ public class RouteActivity extends AbstractMessingActivity { .build(); future.complete(response); } catch (Throwable t) { - if (TopicRouteHelper.isTopicNotExistError(t)) { - future.complete(QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage())) - .build()); - } else { - future.completeExceptionally(t); - } + future.completeExceptionally(t); } return future; } @@ -102,6 +96,7 @@ public class RouteActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); try { + validateTopic(request.getTopic()); List addressList = this.convertToAddressList(request.getEndpoints()); ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index 46eb3e337a..309d94bfce 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -22,11 +22,13 @@ import apache.rocketmq.v2.EndTransactionResponse; import apache.rocketmq.v2.TransactionResolution; import apache.rocketmq.v2.TransactionSource; import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.proxy.common.ProxyContext; 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.GrpcProxyException; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.TransactionStatus; @@ -41,6 +43,11 @@ public class EndTransactionActivity extends AbstractMessingActivity { public CompletableFuture endTransaction(ProxyContext ctx, EndTransactionRequest request) { CompletableFuture future = new CompletableFuture<>(); try { + validateTopic(request.getTopic()); + if (StringUtils.isBlank(request.getTransactionId())) { + throw new GrpcProxyException(Code.INVALID_TRANSACTION_ID, "transaction id cannot be empty"); + } + TransactionStatus transactionStatus = TransactionStatus.UNKNOWN; TransactionResolution transactionResolution = request.getResolution(); switch (transactionResolution) { 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 4815d7dbaf..c223eb4783 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 @@ -36,9 +36,9 @@ public abstract class AbstractProcessor extends AbstractStartAndShutdown { this.serviceManager = serviceManager; } - protected void checkReceiptHandle(ReceiptHandle handle) { + protected void validateReceiptHandle(ReceiptHandle handle) { if (handle.isExpired()) { - throw new ProxyException(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, "receipt handle is expired"); + throw new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "receipt handle is expired"); } } 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 b3862fc0b2..30df54b7c1 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 @@ -170,7 +170,7 @@ public class ConsumerProcessor extends AbstractProcessor { ) { CompletableFuture future = new CompletableFuture<>(); try { - this.checkReceiptHandle(handle); + this.validateReceiptHandle(handle); AckMessageRequestHeader ackMessageRequestHeader = new AckMessageRequestHeader(); ackMessageRequestHeader.setConsumerGroup(consumerGroup); @@ -195,7 +195,7 @@ public class ConsumerProcessor extends AbstractProcessor { String messageId, String groupName, String topicName, long invisibleTime, long timeoutMillis) { CompletableFuture future = new CompletableFuture<>(); try { - this.checkReceiptHandle(handle); + this.validateReceiptHandle(handle); ChangeInvisibleTimeRequestHeader changeInvisibleTimeRequestHeader = new ChangeInvisibleTimeRequestHeader(); changeInvisibleTimeRequestHeader.setConsumerGroup(groupName); 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 6b093bb0c9..c90b4f4be6 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 @@ -143,7 +143,7 @@ public class LocalMessageService implements MessageService { break; } default: { - throw new ProxyException(ProxyExceptionCode.ILLEGAL_MESSAGE, r.getRemark()); + throw new ProxyException(ProxyExceptionCode.INTERNAL_SERVER_ERROR, r.getRemark()); } } sendResult.setSendStatus(sendStatus); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java index 8f833d4c99..c02e033c18 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/message/LocalRemotingCommand.java @@ -16,6 +16,7 @@ */ package org.apache.rocketmq.proxy.service.message; +import java.util.HashMap; import org.apache.rocketmq.remoting.CommandCustomHeader; import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; @@ -26,6 +27,7 @@ public class LocalRemotingCommand extends RemotingCommand { LocalRemotingCommand cmd = new LocalRemotingCommand(); cmd.setCode(code); cmd.writeCustomHeader(customHeader); + cmd.setExtFields(new HashMap<>()); setCmdVersion(cmd); return cmd; } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java new file mode 100644 index 0000000000..3dad901daf --- /dev/null +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java @@ -0,0 +1,77 @@ +/* + * 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.grpc.v2; + +import apache.rocketmq.v2.Resource; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.topic.TopicValidator; +import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; +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.GrpcProxyException; +import org.apache.rocketmq.proxy.processor.MessagingProcessor; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertThrows; + +public class AbstractMessingActivityTest extends InitConfigAndLoggerTest { + + public static class MockMessingActivity extends AbstractMessingActivity { + + public MockMessingActivity(MessagingProcessor messagingProcessor, + GrpcClientSettingsManager grpcClientSettingsManager, + GrpcChannelManager grpcChannelManager) { + super(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + } + } + + private AbstractMessingActivity messingActivity; + + @Before + public void before() throws Throwable { + super.before(); + this.messingActivity = new MockMessingActivity(null, null, null); + } + + @Test + public void testValidateTopic() { + assertThrows(GrpcProxyException.class, () -> messingActivity.validateTopic(Resource.newBuilder().build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateTopic(Resource.newBuilder().setName(TopicValidator.RMQ_SYS_TRACE_TOPIC).build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateTopic(Resource.newBuilder().setName("@").build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateTopic(Resource.newBuilder().setName(createString(128)).build())); + messingActivity.validateTopic(Resource.newBuilder().setName(createString(127)).build()); + } + + @Test + public void testValidateConsumer() { + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(MixAll.CID_SYS_RMQ_TRANS).build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName("@").build())); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(256)).build())); + messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(255)).build()); + } + + private static String createString(int len) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append('a'); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 4682c93403..4d4189dbfb 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -37,11 +37,13 @@ import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; @RunWith(MockitoJUnitRunner.class) public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { @@ -93,7 +95,31 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { grpcMessagingApplication.queryRoute(request, queryRouteResponseStreamObserver); future.complete(response); await().untilAsserted(() -> { - Mockito.verify(queryRouteResponseStreamObserver, Mockito.times(1)).onNext(response); + Mockito.verify(queryRouteResponseStreamObserver, Mockito.times(1)).onNext(Mockito.same(response)); }); } + + @Test + public void testQueryRouteWithBadClientID() { + Metadata metadata = new Metadata(); + metadata.put(InterceptorConstants.LANGUAGE, JAVA); + metadata.put(InterceptorConstants.REMOTE_ADDRESS, REMOTE_ADDR); + metadata.put(InterceptorConstants.LOCAL_ADDRESS, LOCAL_ADDR); + Context.current() + .withValue(InterceptorConstants.METADATA, metadata) + .attach(); + + QueryRouteRequest request = QueryRouteRequest.newBuilder() + .setEndpoints(grpcEndpoints) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .build(); + grpcMessagingApplication.queryRoute(request, queryRouteResponseStreamObserver); + + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(QueryRouteResponse.class); + await().untilAsserted(() -> { + Mockito.verify(queryRouteResponseStreamObserver, Mockito.times(1)).onNext(responseArgumentCaptor.capture()); + }); + + assertEquals(Code.BAD_REQUEST_CLIENT_ID, responseArgumentCaptor.getValue().getStatus().getCode()); + } } \ No newline at end of file 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 523c30bfcf..4df834bb65 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 @@ -21,6 +21,7 @@ import apache.rocketmq.v2.AckMessageEntry; import apache.rocketmq.v2.AckMessageRequest; import apache.rocketmq.v2.AckMessageResponse; import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Resource; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; @@ -41,6 +42,7 @@ public class AckMessageActivityTest extends BaseActivityTest { private AckMessageActivity ackMessageActivity; private static final String TOPIC = "topic"; + private static final String GROUP = "group"; @Before public void before() throws Throwable { @@ -51,7 +53,7 @@ public class AckMessageActivityTest extends BaseActivityTest { @Test public void testAckMessage() throws Throwable { when(this.messagingProcessor.ackMessage(any(), any(), eq("msg1"), anyString(), anyString())) - .thenThrow(new ProxyException(ProxyExceptionCode.RECEIPT_HANDLE_EXPIRED, "receipt handle is expired")); + .thenThrow(new ProxyException(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, "receipt handle is expired")); AckResult msg2AckResult = new AckResult(); msg2AckResult.setStatus(AckStatus.OK); @@ -66,6 +68,8 @@ public class AckMessageActivityTest extends BaseActivityTest { 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)) @@ -83,7 +87,7 @@ public class AckMessageActivityTest extends BaseActivityTest { assertEquals(Code.MULTIPLE_RESULTS, response.getStatus().getCode()); assertEquals(3, response.getEntriesCount()); - assertEquals(Code.RECEIPT_HANDLE_EXPIRED, response.getEntries(0).getStatus().getCode()); + 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()); } 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 448800e941..130d5521dc 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 @@ -30,6 +30,7 @@ import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; import java.util.HashMap; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; @@ -53,6 +54,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -334,4 +336,274 @@ public class SendMessageActivityTest extends BaseActivityTest { assertEquals(firstSelect, thirdSelect); assertNotEquals(firstSelect, secondSelect); } + + @Test + public void testParameterValidate() { + // too large message body + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[4 * 1024 * 1024 + 1])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.MESSAGE_BODY_TOO_LARGE, e.getCode()); + throw e; + } + }); + + // black tag + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setTag(" ") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_TAG, e.getCode()); + throw e; + } + }); + + // tag with '|' + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setTag("|") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_TAG, e.getCode()); + throw e; + } + }); + + // blank message key + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .addKeys(" ") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_KEY, e.getCode()); + throw e; + } + }); + + // blank message group + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageGroup(" ") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_GROUP, e.getCode()); + throw e; + } + }); + + // long message group + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageGroup(createStr(1025)) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_GROUP, e.getCode()); + throw e; + } + }); + + // too large message property + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .putUserProperties("key", createStr(16 * 1024)) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.MESSAGE_PROPERTIES_TOO_LARGE, e.getCode()); + throw e; + } + }); + + // set system properties + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .putUserProperties(MessageConst.PROPERTY_TRACE_SWITCH, "false") + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, e.getCode()); + throw e; + } + }); + + // empty message id + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(" ") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_ID, e.getCode()); + throw e; + } + }); + } + + private static String createStr(int len) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append("a"); + } + return sb.toString(); + } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index ad95e0ed10..ae91ffce93 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -38,12 +38,14 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -109,15 +111,19 @@ public class RouteActivityTest extends BaseActivityTest { when(this.messagingProcessor.getTopicRouteDataForProxy(any(), any(), anyString())) .thenThrow(new MQBrokerException(ResponseCode.TOPIC_NOT_EXIST, "")); - QueryRouteResponse response = this.routeActivity.queryRoute( - createContext(), - QueryRouteRequest.newBuilder() - .setEndpoints(grpcEndpoints) - .setTopic(GRPC_TOPIC) - .build() - ).get(); - - assertEquals(Code.TOPIC_NOT_FOUND, response.getStatus().getCode()); + try { + this.routeActivity.queryRoute( + createContext(), + QueryRouteRequest.newBuilder() + .setEndpoints(grpcEndpoints) + .setTopic(GRPC_TOPIC) + .build() + ).get(); + } catch (Throwable t) { + assertEquals(Code.TOPIC_NOT_FOUND, ResponseBuilder.buildStatus(t).getCode()); + return; + } + fail(); } @Test diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java index e1524e5e8b..e3f6edb997 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/service/message/LocalMessageServiceTest.java @@ -227,7 +227,7 @@ public class LocalMessageServiceTest extends InitConfigAndLoggerTest { CompletableFuture> future = localMessageService.sendMessage(proxyContext, null, messagesList, sendMessageRequestHeader, 1000L); ExecutionException exception = catchThrowableOfType(future::get, ExecutionException.class); assertThat(exception.getCause()).isInstanceOf(ProxyException.class); - assertThat(((ProxyException) exception.getCause()).getCode()).isEqualTo(ProxyExceptionCode.ILLEGAL_MESSAGE); + assertThat(((ProxyException) exception.getCause()).getCode()).isEqualTo(ProxyExceptionCode.INTERNAL_SERVER_ERROR); } @Test diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 85ae8f1faf..99df384d22 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -378,7 +378,7 @@ public class GrpcBaseIT extends BaseConf { for (AckMessageResultEntry entry : ackMessageResponse.getEntriesList()) { if (entry.getStatus().getCode().equals(Code.OK)) { okNum++; - } else if (entry.getStatus().getCode().equals(Code.RECEIPT_HANDLE_EXPIRED)) { + } else if (entry.getStatus().getCode().equals(Code.INVALID_RECEIPT_HANDLE)) { expireNum++; } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index fc113370bc..38954fd8e5 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -38,7 +38,7 @@ public class LocalGrpcIT extends GrpcBaseIT { @Before public void setUp() throws Exception { super.setUp(); - messagingProcessor = DefaultMessagingProcessor.createForClusterMode(); + messagingProcessor = DefaultMessagingProcessor.createForLocalMode(brokerController1); messagingProcessor.start(); grpcMessagingApplication = GrpcMessagingApplication.create(messagingProcessor); grpcMessagingApplication.start(); From 461151c6f5c9e8824352a4075f03b7c01fff44d4 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 15:25:56 +0800 Subject: [PATCH 277/338] [ISSUE #3949] set born host when send and recv message --- .../rocketmq/common/message/MessageConst.java | 1 + .../proxy/grpc/v2/common/GrpcConverter.java | 10 +++++++--- .../grpc/v2/producer/SendMessageActivity.java | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java index d82cc07012..25c73bc265 100644 --- a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java +++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java @@ -68,6 +68,7 @@ public class MessageConst { public static final String PROPERTY_TRACE_CONTEXT = "TRACE_CONTEXT"; public static final String PROPERTY_TIMER_DELAY_SEC = "TIMER_DELAY_SEC"; public static final String PROPERTY_TIMER_DELIVER_MS = "TIMER_DELIVER_MS"; + public static final String PROPERTY_BORN_HOST = "__BORNHOST"; /** * property which name starts with "__RMQ.TRANSIENT." is called transient one that will not stored in broker disks. diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 72db47eccf..19786a32b1 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -45,6 +45,7 @@ import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.common.utils.BinaryUtil; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.remoting.common.RemotingUtil; public class GrpcConverter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); @@ -163,8 +164,11 @@ public class GrpcConverter { systemPropertiesBuilder.setBornTimestamp(Timestamps.fromMillis(bornTimestamp)); // born_host - String bornHostString = messageExt.getBornHostString(); - if (bornHostString != null) { + String bornHostString = messageExt.getProperty(MessageConst.PROPERTY_BORN_HOST); + if (StringUtils.isBlank(bornHostString)) { + bornHostString = messageExt.getBornHostString(); + } + if (StringUtils.isNotBlank(bornHostString)) { systemPropertiesBuilder.setBornHost(bornHostString); } @@ -175,7 +179,7 @@ public class GrpcConverter { // store_host SocketAddress storeHost = messageExt.getStoreHost(); if (storeHost != null) { - systemPropertiesBuilder.setStoreHost(storeHost.toString()); + systemPropertiesBuilder.setStoreHost(RemotingUtil.socketAddress2String(storeHost)); } // delivery_timestamp 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 117fc7b007..94a51a72df 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 @@ -97,19 +97,19 @@ public class SendMessageActivity extends AbstractMessingActivity { throw new GrpcProxyException(Code.MESSAGE_CORRUPTED, "topic in message is not same"); } // here use topicName as producerGroup for transactional checker. - messageExtList.add(buildMessage(protoMessage, topicName)); + messageExtList.add(buildMessage(context, protoMessage, topicName)); } return messageExtList; } - protected Message buildMessage(apache.rocketmq.v2.Message protoMessage, String producerGroup) { + protected Message buildMessage(ProxyContext context, apache.rocketmq.v2.Message protoMessage, String producerGroup) { String topicName = GrpcConverter.wrapResourceWithNamespace(protoMessage.getTopic()); validateMessageBodySize(protoMessage.getBody()); Message messageExt = new Message(); messageExt.setTopic(topicName); messageExt.setBody(protoMessage.getBody().toByteArray()); - Map messageProperty = this.buildMessageProperty(protoMessage, producerGroup); + Map messageProperty = this.buildMessageProperty(context, protoMessage, producerGroup); MessageAccessor.setProperties(messageExt, messageProperty); return messageExt; @@ -189,7 +189,7 @@ public class SendMessageActivity extends AbstractMessingActivity { } } - protected Map buildMessageProperty(apache.rocketmq.v2.Message message, String producerGroup) { + protected Map buildMessageProperty(ProxyContext context, apache.rocketmq.v2.Message message, String producerGroup) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties Map userProperties = message.getUserPropertiesMap(); @@ -256,6 +256,14 @@ public class SendMessageActivity extends AbstractMessingActivity { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRACE_CONTEXT, traceContext); } + String bornHost = message.getSystemProperties().getBornHost(); + if (StringUtils.isBlank(bornHost)) { + bornHost = context.getRemoteAddress(); + } + if (StringUtils.isNotBlank(bornHost)) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_BORN_HOST, bornHost); + } + validateMessagePropertySize(messageWithHeader.getProperties()); return messageWithHeader.getProperties(); } From 9d211f921fb3419810b6c49bc9d3b0a3a7775876 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 17:52:28 +0800 Subject: [PATCH 278/338] [ISSUE #3949] change default transactionCheckImmunityTime config --- .../org/apache/rocketmq/proxy/config/ProxyConfig.java | 10 +++++----- .../proxy/grpc/v2/producer/SendMessageActivity.java | 7 ++++++- .../transaction/AbstractTransactionService.java | 6 +++--- 3 files changed, 14 insertions(+), 9 deletions(-) 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 eb7044a853..2d8b57db97 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 @@ -118,7 +118,7 @@ public class ProxyConfig { private int transactionHeartbeatBatchNum = 100; private long transactionDataExpireScanPeriodMillis = Duration.ofSeconds(10).toMillis(); private long transactionDataMaxWaitClearMillis = Duration.ofSeconds(30).toMillis(); - private long defaultTransactionCheckImmunityTimeInMills = Duration.ofMillis(1).toMillis(); + private long defaultTransactionCheckImmunityTimeInSecond = 60; private long longPollingReserveTimeInMillis = 100; @@ -600,12 +600,12 @@ public class ProxyConfig { this.transactionDataMaxWaitClearMillis = transactionDataMaxWaitClearMillis; } - public long getDefaultTransactionCheckImmunityTimeInMills() { - return defaultTransactionCheckImmunityTimeInMills; + public long getDefaultTransactionCheckImmunityTimeInSecond() { + return defaultTransactionCheckImmunityTimeInSecond; } - public void setDefaultTransactionCheckImmunityTimeInMills(long defaultTransactionCheckImmunityTimeInMills) { - this.defaultTransactionCheckImmunityTimeInMills = defaultTransactionCheckImmunityTimeInMills; + public void setDefaultTransactionCheckImmunityTimeInSecond(long defaultTransactionCheckImmunityTimeInSecond) { + this.defaultTransactionCheckImmunityTimeInSecond = defaultTransactionCheckImmunityTimeInSecond; } public long getLongPollingReserveTimeInMillis() { 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 94a51a72df..f8a11fa3d6 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 @@ -226,7 +226,12 @@ public class SendMessageActivity extends AbstractMessingActivity { if (messageType.equals(MessageType.TRANSACTION)) { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); - Duration transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); + Duration transactionResolveDelay; + if (!message.getSystemProperties().hasOrphanedTransactionRecoveryDuration()) { + transactionResolveDelay = Durations.fromSeconds(ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInSecond()); + } else { + transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); + } MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, String.valueOf(Durations.toSeconds(transactionResolveDelay))); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java index 504cbb6134..6390bf97ad 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java @@ -80,15 +80,15 @@ public abstract class AbstractTransactionService implements TransactionService, } protected long parseCheckImmunityTime(Message message) { - long checkImmunityTime = ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInMills(); + long checkImmunityTime = ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInSecond(); String checkImmunityTimeStr = message.getProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS); if (StringUtils.isNotBlank(checkImmunityTimeStr)) { try { - checkImmunityTime = Duration.ofSeconds(Long.parseLong(checkImmunityTimeStr)).toMillis(); + checkImmunityTime = Long.parseLong(checkImmunityTimeStr); } catch (Exception ignored) { } } - return checkImmunityTime; + return Duration.ofSeconds(checkImmunityTime).toMillis(); } protected abstract String getBrokerNameByAddr(String brokerAddr); From 681608f6655ed248cb644ed3909cba91ecc12a7e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 20:25:11 +0800 Subject: [PATCH 279/338] [ISSUE #3949] change response code --- .../apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java | 2 +- .../apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index f9f2760e1d..218099f178 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -181,7 +181,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected void validateContext(ProxyContext context) { if (StringUtils.isBlank(context.getClientID())) { - throw new GrpcProxyException(Code.BAD_REQUEST_CLIENT_ID, "client id cannot be empty"); + throw new GrpcProxyException(Code.CLIENT_ID_REQUIRED, "client id cannot be empty"); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 08f251096c..eaa6f9a561 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -295,7 +295,7 @@ public class ClientActivity extends AbstractMessingActivity { ConsumerRunningInfo runningInfo = new ConsumerRunningInfo(); runningInfo.setJstack(threadStack); responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SUCCESS, "", runningInfo)); - } else if (status.getCode().equals(Code.VERIFY_MESSAGE_FORBIDDEN)) { + } else if (status.getCode().equals(Code.VERIFY_FIFO_MESSAGE_UNSUPPORTED)) { responseFuture.complete(new ProxyRelayResult<>(ResponseCode.NO_PERMISSION, "forbidden to verify message", null)); } else { responseFuture.complete(new ProxyRelayResult<>(ResponseCode.SYSTEM_ERROR, "verify message failed", null)); From 5592cab67032e482a66d1dd2d04741b28ba80000 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 20:26:30 +0800 Subject: [PATCH 280/338] [ISSUE #3949] report error info in end transaction --- .../proxy/common/ProxyExceptionCode.java | 1 + .../grpc/v2/common/GrpcProxyException.java | 2 +- .../transaction/EndTransactionActivity.java | 10 ++-- .../processor/DefaultMessagingProcessor.java | 6 +-- .../proxy/processor/MessagingProcessor.java | 10 ++-- .../proxy/processor/TransactionProcessor.java | 48 +++++++++++-------- .../message/ClusterMessageService.java | 23 +++++---- .../service/message/LocalMessageService.java | 9 ++-- .../proxy/service/message/MessageService.java | 4 +- .../grpc/v2/GrpcMessagingApplicationTest.java | 2 +- .../EndTransactionActivityTest.java | 6 ++- .../processor/TransactionProcessorTest.java | 3 +- 12 files changed, 72 insertions(+), 52 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 1fd501a41b..34bb44d103 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.common; public enum ProxyExceptionCode { INVALID_BROKER_NAME, + TRANSACTION_DATA_NOT_FOUND, FORBIDDEN, MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, INVALID_RECEIPT_HANDLE, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index 0d055afcea..c36dc1878a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -27,7 +27,7 @@ public class GrpcProxyException extends RuntimeException { private ProxyException proxyException; private Code code; - private static final Map CODE_MAPPING = new HashMap<>(); + public static final Map CODE_MAPPING = new HashMap<>(); static { CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.BAD_REQUEST); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index 309d94bfce..9e12238c2f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -60,16 +60,16 @@ public class EndTransactionActivity extends AbstractMessingActivity { default: break; } - this.messagingProcessor.endTransaction( + future = this.messagingProcessor.endTransaction( ctx, request.getTransactionId(), request.getMessageId(), GrpcConverter.wrapResourceWithNamespace(request.getTopic()), transactionStatus, - request.getSource().equals(TransactionSource.SOURCE_SERVER_CHECK)); - future.complete(EndTransactionResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) - .build()); + request.getSource().equals(TransactionSource.SOURCE_SERVER_CHECK)) + .thenApply(r -> EndTransactionResponse.newBuilder() + .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .build()); } catch (Throwable t) { future.completeExceptionally(t); } 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 07aae54191..a9335cb229 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 @@ -140,10 +140,10 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen } @Override - public void endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, + public CompletableFuture endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck, - long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { - this.transactionProcessor.endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, timeoutMillis); + long timeoutMillis) { + return this.transactionProcessor.endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, timeoutMillis); } @Override 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 5320426d58..ade7c45db1 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 @@ -100,18 +100,18 @@ public interface MessagingProcessor extends StartAndShutdown { long timeoutMillis ); - default void endTransaction( + default CompletableFuture endTransaction( ProxyContext ctx, String transactionId, String messageId, String producerGroup, TransactionStatus transactionStatus, boolean fromTransactionCheck - ) throws MQBrokerException, RemotingException, InterruptedException { - endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, DEFAULT_TIMEOUT_MILLS); + ) { + return endTransaction(ctx, transactionId, messageId, producerGroup, transactionStatus, fromTransactionCheck, DEFAULT_TIMEOUT_MILLS); } - void endTransaction( + CompletableFuture endTransaction( ProxyContext ctx, String transactionId, String messageId, @@ -119,7 +119,7 @@ public interface MessagingProcessor extends StartAndShutdown { TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis - ) throws MQBrokerException, RemotingException, InterruptedException; + ); CompletableFuture popMessage( ProxyContext ctx, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java index 76517861e9..3b284cd056 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/TransactionProcessor.java @@ -16,12 +16,13 @@ */ package org.apache.rocketmq.proxy.processor; -import org.apache.rocketmq.client.exception.MQBrokerException; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.sysflag.MessageSysFlag; 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.service.ServiceManager; import org.apache.rocketmq.proxy.service.transaction.EndTransactionRequestData; -import org.apache.rocketmq.remoting.exception.RemotingException; public class TransactionProcessor extends AbstractProcessor { @@ -30,26 +31,31 @@ public class TransactionProcessor extends AbstractProcessor { super(messagingProcessor, serviceManager); } - void endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, - TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) - throws MQBrokerException, RemotingException, InterruptedException { - - EndTransactionRequestData headerData = serviceManager.getTransactionService().genEndTransactionRequestHeader( - producerGroup, - buildCommitOrRollback(transactionStatus), - fromTransactionCheck, - messageId, - transactionId - ); - if (headerData == null) { - return; + public CompletableFuture endTransaction(ProxyContext ctx, String transactionId, String messageId, String producerGroup, + TransactionStatus transactionStatus, boolean fromTransactionCheck, long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + EndTransactionRequestData headerData = serviceManager.getTransactionService().genEndTransactionRequestHeader( + producerGroup, + buildCommitOrRollback(transactionStatus), + fromTransactionCheck, + messageId, + transactionId + ); + if (headerData == null) { + future.completeExceptionally(new ProxyException(ProxyExceptionCode.TRANSACTION_DATA_NOT_FOUND, "cannot found transaction data")); + return future; + } + return this.serviceManager.getMessageService().endTransactionOneway( + ctx, + headerData.getBrokerName(), + headerData.getRequestHeader(), + timeoutMillis + ); + } catch (Throwable t) { + future.completeExceptionally(t); } - this.serviceManager.getMessageService().endTransactionOneway( - ctx, - headerData.getBrokerName(), - headerData.getRequestHeader(), - timeoutMillis - ); + return future; } protected int buildCommitOrRollback(TransactionStatus transactionStatus) { 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 6f710e10cc..30faf38f2a 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 @@ -88,14 +88,21 @@ public class ClusterMessageService implements MessageService { } @Override - public void endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, - long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { - this.mqClientAPIFactory.getClient().endTransactionOneway( - this.resolveBrokerAddr(brokerName), - requestHeader, - "end transaction from proxy", - timeoutMillis - ); + public CompletableFuture endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); + try { + this.mqClientAPIFactory.getClient().endTransactionOneway( + this.resolveBrokerAddr(brokerName), + requestHeader, + "end transaction from proxy", + timeoutMillis + ); + future.complete(null); + } catch (Throwable t) { + future.completeExceptionally(t); + } + return future; } @Override 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 c90b4f4be6..0281d43b1e 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 @@ -175,17 +175,20 @@ public class LocalMessageService implements MessageService { } @Override - public void endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, - long timeoutMillis) throws MQBrokerException, RemotingException, InterruptedException { + public CompletableFuture endTransactionOneway(ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, + long timeoutMillis) { + CompletableFuture future = new CompletableFuture<>(); SimpleChannel channel = channelManager.createChannel(ctx); ChannelHandlerContext channelHandlerContext = channel.getChannelHandlerContext(); RemotingCommand command = LocalRemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader); try { brokerController.getEndTransactionProcessor() .processRequest(channelHandlerContext, command); + future.complete(null); } catch (Exception e) { - log.error("Fail to process endTransaction command", e); + future.completeExceptionally(e); } + return future; } @Override 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 5b63aa284c..2ea351ca79 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 @@ -63,12 +63,12 @@ public interface MessageService { long timeoutMillis ); - void endTransactionOneway( + CompletableFuture endTransactionOneway( ProxyContext ctx, String brokerName, EndTransactionRequestHeader requestHeader, long timeoutMillis - ) throws MQBrokerException, RemotingException, InterruptedException; + ); CompletableFuture popMessage( ProxyContext ctx, diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 4d4189dbfb..74a0815c4a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -120,6 +120,6 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { Mockito.verify(queryRouteResponseStreamObserver, Mockito.times(1)).onNext(responseArgumentCaptor.capture()); }); - assertEquals(Code.BAD_REQUEST_CLIENT_ID, responseArgumentCaptor.getValue().getStatus().getCode()); + assertEquals(Code.CLIENT_ID_REQUIRED, responseArgumentCaptor.getValue().getStatus().getCode()); } } \ No newline at end of file diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java index 3a6e46c486..0a3992990a 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivityTest.java @@ -25,6 +25,7 @@ import apache.rocketmq.v2.TransactionResolution; import apache.rocketmq.v2.TransactionSource; import java.util.Arrays; import java.util.Collection; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.processor.TransactionStatus; @@ -38,6 +39,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; @RunWith(Parameterized.class) public class EndTransactionActivityTest extends BaseActivityTest { @@ -66,9 +68,9 @@ public class EndTransactionActivityTest extends BaseActivityTest { public void testEndTransaction() throws Throwable { ArgumentCaptor transactionStatusCaptor = ArgumentCaptor.forClass(TransactionStatus.class); ArgumentCaptor fromTransactionCheckCaptor = ArgumentCaptor.forClass(Boolean.class); - doNothing().when(this.messagingProcessor).endTransaction(any(), any(), anyString(), anyString(), + when(this.messagingProcessor.endTransaction(any(), any(), anyString(), anyString(), transactionStatusCaptor.capture(), - fromTransactionCheckCaptor.capture()); + fromTransactionCheckCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null)); EndTransactionResponse response = this.endTransactionActivity.endTransaction( createContext(), diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java index 8fe8c0d10a..c21ad3dda3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/TransactionProcessorTest.java @@ -17,6 +17,7 @@ package org.apache.rocketmq.proxy.processor; +import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.service.transaction.EndTransactionRequestData; @@ -52,7 +53,7 @@ public class TransactionProcessorTest extends BaseProcessorTest { } protected void testEndTransaction(int sysFlag, TransactionStatus transactionStatus) throws Throwable { - doNothing().when(this.messageService).endTransactionOneway(any(), any(), any(), anyLong()); + when(this.messageService.endTransactionOneway(any(), any(), any(), anyLong())).thenReturn(CompletableFuture.completedFuture(null)); ArgumentCaptor commitOrRollbackCaptor = ArgumentCaptor.forClass(Integer.class); when(transactionService.genEndTransactionRequestHeader(anyString(), commitOrRollbackCaptor.capture(), anyBoolean(), anyString(), anyString())) .thenReturn(new EndTransactionRequestData("brokerName", new EndTransactionRequestHeader())); From fddac7892583b7e2210ad0d2ed7399db04373f74 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 20:36:26 +0800 Subject: [PATCH 281/338] [ISSUE #3949] change to use ConcurrentHashMap --- .../rocketmq/proxy/grpc/v2/common/GrpcProxyException.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index c36dc1878a..2ae80e1fcb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.proxy.grpc.v2.common; import apache.rocketmq.v2.Code; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.rocketmq.proxy.common.ProxyException; import org.apache.rocketmq.proxy.common.ProxyExceptionCode; @@ -27,7 +27,7 @@ public class GrpcProxyException extends RuntimeException { private ProxyException proxyException; private Code code; - public static final Map CODE_MAPPING = new HashMap<>(); + public static final Map CODE_MAPPING = new ConcurrentHashMap<>(); static { CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.BAD_REQUEST); From 0ff2c2fb69bb7356c722ad250f7e0da02c06fb92 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 29 Jun 2022 20:36:37 +0800 Subject: [PATCH 282/338] [ISSUE #3949] for checkstyle --- .../rocketmq/proxy/processor/DefaultMessagingProcessor.java | 2 -- .../org/apache/rocketmq/proxy/processor/MessagingProcessor.java | 2 -- .../rocketmq/proxy/service/message/ClusterMessageService.java | 2 -- .../rocketmq/proxy/service/message/LocalMessageService.java | 2 -- .../apache/rocketmq/proxy/service/message/MessageService.java | 2 -- 5 files changed, 10 deletions(-) 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 a9335cb229..23dd3c86a5 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 @@ -30,7 +30,6 @@ import org.apache.rocketmq.broker.client.ProducerChangeListener; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; @@ -52,7 +51,6 @@ import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class DefaultMessagingProcessor extends AbstractStartAndShutdown implements MessagingProcessor { 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 ade7c45db1..35015b6aee 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 @@ -28,7 +28,6 @@ import org.apache.rocketmq.broker.client.ProducerChangeListener; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.consumer.ReceiptHandle; @@ -44,7 +43,6 @@ import org.apache.rocketmq.proxy.common.StartAndShutdown; import org.apache.rocketmq.proxy.service.metadata.MetadataService; import org.apache.rocketmq.proxy.service.relay.ProxyRelayService; import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData; -import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface MessagingProcessor extends StartAndShutdown { 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 30faf38f2a..e5b7e95330 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 @@ -23,7 +23,6 @@ import java.util.concurrent.CompletableFuture; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; @@ -47,7 +46,6 @@ import org.apache.rocketmq.proxy.common.ProxyExceptionCode; import org.apache.rocketmq.proxy.service.mqclient.MQClientAPIFactory; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.proxy.service.route.TopicRouteService; -import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public class ClusterMessageService implements MessageService { 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 0281d43b1e..d61ec0342c 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 @@ -32,7 +32,6 @@ import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.client.consumer.PullResult; -import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.constant.LoggerName; @@ -71,7 +70,6 @@ import org.apache.rocketmq.proxy.service.channel.InvocationContext; import org.apache.rocketmq.proxy.service.channel.SimpleChannel; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; import org.apache.rocketmq.remoting.RPCHook; -import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 2ea351ca79..ee35fa03f2 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 @@ -22,7 +22,6 @@ import java.util.concurrent.CompletableFuture; 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.exception.MQBrokerException; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; @@ -42,7 +41,6 @@ import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; -import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; public interface MessageService { From 161dcdc3eb65d3e84974970c118e793c85596423 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 30 Jun 2022 14:02:04 +0800 Subject: [PATCH 283/338] [ISSUE #3949] add consume message orderly IT --- .../rocketmq/test/grpc/v2/ClusterGrpcIT.java | 5 + .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 110 ++++++++++++++---- .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 5 + 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index fa0a6ca7e8..f97b7c1f9f 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -102,4 +102,9 @@ public class ClusterGrpcIT extends GrpcBaseIT { public void testSimpleConsumerToDLQ() throws Exception { super.testSimpleConsumerToDLQ(); } + + @Test + public void testConsumeOrderly() throws Exception { + super.testConsumeOrderly(); + } } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 99df384d22..667f5a096e 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -92,8 +92,10 @@ import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor; import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor; @@ -105,6 +107,7 @@ import org.apache.rocketmq.test.util.MQRandomUtils; import org.apache.rocketmq.test.util.RandomUtils; import org.junit.Rule; +import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; @@ -145,6 +148,7 @@ public class GrpcBaseIT extends BaseConf { ConfigurationManager.getProxyConfig().setNameSrvAddr(nsAddr); // Set LongPollingReserveTimeInMillis to 500ms to reserve more time for IT ConfigurationManager.getProxyConfig().setLongPollingReserveTimeInMillis(500); + ConfigurationManager.getProxyConfig().setRocketMQClusterName(brokerController1.getBrokerConfig().getBrokerClusterName()); blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); @@ -226,7 +230,7 @@ public class GrpcBaseIT extends BaseConf { try { requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setSettings(buildPushConsumerClientSettings()) + .setSettings(buildPushConsumerClientSettings(group)) .build()); await().atMost(java.time.Duration.ofSeconds(3)).until(() -> { if (telemetryCommandRef.get() == null) { @@ -281,7 +285,7 @@ public class GrpcBaseIT extends BaseConf { assertEndTransactionResponse(endTransactionResponse); requestStreamObserver.onNext(TelemetryCommand.newBuilder() - .setSettings(buildPushConsumerClientSettings()) + .setSettings(buildPushConsumerClientSettings(group)) .build()); await().atMost(java.time.Duration.ofSeconds(30)).until(() -> { @@ -310,11 +314,10 @@ public class GrpcBaseIT extends BaseConf { String group = MQRandomUtils.getRandomConsumerGroup(); int maxDeliveryAttempts = 16; - boolean fifo = false; int bodySize = 4 * 1024; // init consumer offset - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); @@ -322,7 +325,7 @@ public class GrpcBaseIT extends BaseConf { SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendBigMessageRequest(topic, messageId, bodySize)); assertSendMessage(sendResponse, messageId); - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); assertThat(message.getSystemProperties().getBodyEncoding()).isEqualTo(Encoding.GZIP); @@ -332,11 +335,9 @@ public class GrpcBaseIT extends BaseConf { public void testSimpleConsumerSendAndRecv() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); - int maxDeliveryAttempts = 16; - boolean fifo = false; // init consumer offset - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); @@ -344,7 +345,7 @@ public class GrpcBaseIT extends BaseConf { SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); Message message = assertAndGetReceiveMessage(receiveMessage(blockingStub, topic, group), messageId); @@ -390,10 +391,15 @@ public class GrpcBaseIT extends BaseConf { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); int maxDeliveryAttempts = 2; - boolean fifo = false; + + SubscriptionGroupConfig groupConfig = brokerController1.getSubscriptionGroupManager().findSubscriptionGroupConfig(group); + groupConfig.setRetryMaxTimes(maxDeliveryAttempts); + brokerController1.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); + brokerController2.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); + brokerController3.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); // init consumer offset - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); receiveMessage(blockingStub, topic, group, 1); this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); @@ -401,7 +407,7 @@ public class GrpcBaseIT extends BaseConf { SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendMessageRequest(topic, messageId)); assertSendMessage(sendResponse, messageId); - this.sendClientSettings(stub, buildSimpleConsumerClientSettings(maxDeliveryAttempts, fifo)).get(); + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); AtomicInteger receiveMessageCount = new AtomicInteger(0); @@ -430,6 +436,50 @@ public class GrpcBaseIT extends BaseConf { assertThat(receiveMessageCount.get()).isEqualTo(maxDeliveryAttempts); } + public void testConsumeOrderly() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name, TopicMessageType.FIFO); + String group = MQRandomUtils.getRandomConsumerGroup(); + + SubscriptionGroupConfig groupConfig = brokerController1.getSubscriptionGroupManager().findSubscriptionGroupConfig(group); + groupConfig.setConsumeMessageOrderly(true); + brokerController1.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); + brokerController2.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); + brokerController3.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); + + this.sendClientSettings(stub, buildPushConsumerClientSettings(group)).get(); + receiveMessage(blockingStub, topic, group, 1); + + String messageGroup = "group"; + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + List messageIdList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + String messageId = createUniqID(); + messageIdList.add(messageId); + SendMessageResponse sendResponse = blockingStub.sendMessage(buildSendOrderMessageRequest(topic, messageId, messageGroup)); + assertSendMessage(sendResponse, messageId); + } + + List messageRecvList = new ArrayList<>(); + this.sendClientSettings(stub, buildPushConsumerClientSettings(group)).get(); + await().atMost(java.time.Duration.ofSeconds(20)).until(() -> { + List retryMessageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group)); + if (retryMessageList.isEmpty()) { + return false; + } + for (Message message : retryMessageList) { + String messageId = message.getSystemProperties().getMessageId(); + messageRecvList.add(messageId); + blockingStub.ackMessage(buildAckMessageRequest(topic, group, + AckMessageEntry.newBuilder().setMessageId(messageId).setReceiptHandle(message.getSystemProperties().getReceiptHandle()).build())); + } + return messageRecvList.size() == messageIdList.size(); + }); + + for (int i = 0; i < messageIdList.size(); i++) { + assertThat(messageRecvList.get(i)).isEqualTo(messageIdList.get(i)); + } + } + public List receiveMessage(MessagingServiceGrpc.MessagingServiceBlockingStub stub, String topic, String group) { return receiveMessage(stub, topic, group, 15); @@ -491,6 +541,25 @@ public class GrpcBaseIT extends BaseConf { .build(); } + public SendMessageRequest buildSendOrderMessageRequest(String topic, String messageId, String messageGroup) { + return SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(messageId) + .setQueueId(0) + .setMessageType(MessageType.FIFO) + .setMessageGroup(messageGroup) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFromUtf8("123")) + .build()) + .build(); + } + public SendMessageRequest buildSendBigMessageRequest(String topic, String messageId, int messageSize) { return SendMessageRequest.newBuilder() .addMessages(Message.newBuilder() @@ -540,7 +609,7 @@ public class GrpcBaseIT extends BaseConf { .build()) .setId(-1) .build()) - .setBatchSize(16) + .setBatchSize(1) .setInvisibleDuration(Duration.newBuilder() .setSeconds(3) .build()) @@ -634,30 +703,27 @@ public class GrpcBaseIT extends BaseConf { .build(); } - public Settings buildSimpleConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + public Settings buildSimpleConsumerClientSettings(String group) { return Settings.newBuilder() .setClientType(ClientType.SIMPLE_CONSUMER) - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(maxDeliveryAttempts) - .build()) .setSubscription(Subscription.newBuilder() - .setFifo(fifo) + .setGroup(Resource.newBuilder().setName(group).build()) .build()) .build(); } - public Settings buildPushConsumerClientSettings() { - return buildPushConsumerClientSettings(2, false); + public Settings buildPushConsumerClientSettings(String group) { + return buildPushConsumerClientSettings(2, group); } - public Settings buildPushConsumerClientSettings(int maxDeliveryAttempts, boolean fifo) { + public Settings buildPushConsumerClientSettings(int maxDeliveryAttempts, String group) { return Settings.newBuilder() .setClientType(ClientType.PUSH_CONSUMER) .setBackoffPolicy(RetryPolicy.newBuilder() .setMaxAttempts(maxDeliveryAttempts) .build()) .setSubscription(Subscription.newBuilder() - .setFifo(fifo) + .setGroup(Resource.newBuilder().setName(group).build()) .build()) .build(); } diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 38954fd8e5..84e819f203 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -89,4 +89,9 @@ public class LocalGrpcIT extends GrpcBaseIT { public void testSimpleConsumerToDLQ() throws Exception { super.testSimpleConsumerToDLQ(); } + + @Test + public void testConsumeOrderly() throws Exception { + super.testConsumeOrderly(); + } } From b117d697c7bb461be2f0e61598c55ceb40e45e11 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 30 Jun 2022 14:03:27 +0800 Subject: [PATCH 284/338] [ISSUE #3949] config renewMaxTimeMillis --- .../org/apache/rocketmq/proxy/config/ProxyConfig.java | 9 +++++++++ .../proxy/grpc/v2/consumer/ReceiveMessageActivity.java | 7 +++---- 2 files changed, 12 insertions(+), 4 deletions(-) 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 2d8b57db97..70c02e2c6c 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 @@ -126,6 +126,7 @@ public class ProxyConfig { private boolean enableProxyAutoRenew = true; private long renewAheadTimeMillis = TimeUnit.SECONDS.toMillis(10); private long renewSliceTimeMillis = TimeUnit.SECONDS.toMillis(60); + private long renewMaxTimeMillis = TimeUnit.HOURS.toMillis(3); private long renewSchedulePeriodMillis = TimeUnit.SECONDS.toMillis(5); private boolean enableACL = false; @@ -664,6 +665,14 @@ public class ProxyConfig { this.renewSliceTimeMillis = renewSliceTimeMillis; } + public long getRenewMaxTimeMillis() { + return renewMaxTimeMillis; + } + + public void setRenewMaxTimeMillis(long renewMaxTimeMillis) { + this.renewMaxTimeMillis = renewMaxTimeMillis; + } + public long getRenewSchedulePeriodMillis() { return renewSchedulePeriodMillis; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index db345d468d..8c4dcb78d9 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -79,11 +79,10 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { return; } - final long requestInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); - long actualInvisibleTime = requestInvisibleTime; + long actualInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { - actualInvisibleTime = Math.min(actualInvisibleTime, proxyConfig.getRenewSliceTimeMillis()); + actualInvisibleTime = proxyConfig.getRenewSliceTimeMillis(); } validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); @@ -124,7 +123,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { if (receiptHandle != null) { MessageReceiptHandle messageReceiptHandle = new MessageReceiptHandle(group, topic, messageExt.getQueueId(), receiptHandle, messageExt.getMsgId(), - messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), requestInvisibleTime); + messageExt.getQueueOffset(), messageExt.getReconsumeTimes(), proxyConfig.getRenewMaxTimeMillis()); receiptHandleProcessor.addReceiptHandle(ctx.getClientID(), group, messageExt.getMsgId(), receiptHandle, messageReceiptHandle); } } From 39e0a706c2b1ba0d24b39ecb8ab08eae12759f80 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 30 Jun 2022 18:59:33 +0800 Subject: [PATCH 285/338] [ISSUE #3949] validate parameters --- .../apache/rocketmq/proxy/common/ProxyExceptionCode.java | 2 +- .../rocketmq/proxy/grpc/v2/client/ClientActivity.java | 8 +++++--- .../rocketmq/proxy/grpc/v2/common/GrpcProxyException.java | 2 +- .../rocketmq/proxy/grpc/v2/route/RouteActivity.java | 2 +- .../validator/DefaultTopicMessageTypeValidator.java | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java index 34bb44d103..4f91388215 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyExceptionCode.java @@ -20,7 +20,7 @@ public enum ProxyExceptionCode { INVALID_BROKER_NAME, TRANSACTION_DATA_NOT_FOUND, FORBIDDEN, - MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, + MESSAGE_PROPERTY_CONFLICT_WITH_TYPE, INVALID_RECEIPT_HANDLE, INTERNAL_SERVER_ERROR, } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index eaa6f9a561..8bacbc6f85 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -105,7 +105,6 @@ public class ClientActivity extends AbstractMessingActivity { switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - validateTopic(topic); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -240,8 +239,7 @@ public class ClientActivity extends AbstractMessingActivity { protected TelemetryCommand processClientSettings(ProxyContext ctx, TelemetryCommand request, StreamObserver responseObserver) { String clientId = ctx.getClientID(); - grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); - Settings settings = grpcClientSettingsManager.getClientSettings(ctx); + Settings settings = request.getSettings(); // Construct metric according to the proxy config final ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); final MetricCollectorMode metricCollectorMode = @@ -269,6 +267,7 @@ public class ClientActivity extends AbstractMessingActivity { settings = settings.toBuilder().setMetric(metric).build(); if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { + validateTopic(topic); String topicName = GrpcConverter.wrapResourceWithNamespace(topic); GrpcClientChannel producerChannel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); producerChannel.setClientObserver(responseObserver); @@ -279,6 +278,9 @@ public class ClientActivity extends AbstractMessingActivity { GrpcClientChannel consumerChannel = this.grpcChannelManager.createChannel(ctx, groupName, clientId); consumerChannel.setClientObserver(responseObserver); } + + grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); + settings = grpcClientSettingsManager.getClientSettings(ctx); return TelemetryCommand.newBuilder() .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) .setSettings(settings) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index 2ae80e1fcb..aa2fd45044 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -34,7 +34,7 @@ public class GrpcProxyException extends RuntimeException { CODE_MAPPING.put(ProxyExceptionCode.INVALID_RECEIPT_HANDLE, Code.INVALID_RECEIPT_HANDLE); CODE_MAPPING.put(ProxyExceptionCode.FORBIDDEN, Code.FORBIDDEN); CODE_MAPPING.put(ProxyExceptionCode.INTERNAL_SERVER_ERROR, Code.INTERNAL_SERVER_ERROR); - CODE_MAPPING.put(ProxyExceptionCode.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, Code.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE); + CODE_MAPPING.put(ProxyExceptionCode.MESSAGE_PROPERTY_CONFLICT_WITH_TYPE, Code.MESSAGE_PROPERTY_CONFLICT_WITH_TYPE); } public GrpcProxyException(Code code, String message) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index 5967220456..4d12f78176 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -96,7 +96,7 @@ public class RouteActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); try { - validateTopic(request.getTopic()); + validateTopicAndConsumerGroup(request.getTopic(), request.getGroup()); List addressList = this.convertToAddressList(request.getEndpoints()); ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java index eaa4144c5f..476fbbebb7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/validator/DefaultTopicMessageTypeValidator.java @@ -25,7 +25,7 @@ public class DefaultTopicMessageTypeValidator implements TopicMessageTypeValidat public void validate(TopicMessageType topicMessageType, TopicMessageType messageType) { if (messageType.equals(TopicMessageType.UNSPECIFIED) || !messageType.equals(topicMessageType)) { - throw new ProxyException(ProxyExceptionCode.MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE, messageType.name() + " " + topicMessageType.name()); + throw new ProxyException(ProxyExceptionCode.MESSAGE_PROPERTY_CONFLICT_WITH_TYPE, messageType.name() + " " + topicMessageType.name()); } } } From fd0973ebd6ede809c57e2ff0fdc19f7c8bc08a67 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 30 Jun 2022 20:16:48 +0800 Subject: [PATCH 286/338] [ISSUE #3949] bug fix for receipt handle renew --- .../grpc/v2/DefaultGrpcMessingActivity.java | 6 +++ .../processor/ReceiptHandleProcessor.java | 53 +++++++++++++------ .../grpc/v2/route/RouteActivityTest.java | 7 +++ .../processor/ReceiptHandleProcessorTest.java | 13 +++-- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java index 5cc6be5951..8cac746bf6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/DefaultGrpcMessingActivity.java @@ -85,6 +85,12 @@ public class DefaultGrpcMessingActivity extends AbstractStartAndShutdown impleme this.endTransactionActivity = new EndTransactionActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); this.routeActivity = new RouteActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); this.clientActivity = new ClientActivity(messagingProcessor, grpcClientSettingsManager, grpcChannelManager); + + this.init(); + } + + protected void init() { + this.appendStartAndShutdown(this.receiptHandleProcessor); } @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index e292bc84a6..0c8b2fdd74 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -26,6 +26,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import org.apache.commons.lang3.tuple.Pair; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerGroupEvent; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; @@ -108,6 +109,17 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); for (Map.Entry entry : receiptHandleGroupMap.entrySet()) { String key = entry.getKey(); + Pair clientIdAndGroup = parseKey(key); + if (clientIdAndGroup == null) { + log.warn("client id and group is empty. key:{}, receiptHandleGroup:{}", key, entry.getValue()); + clearGroup(key); + continue; + } + if (clientIsOffline(clientIdAndGroup.getLeft(), clientIdAndGroup.getRight())) { + clearGroup(key); + continue; + } + ReceiptHandleGroup group = entry.getValue(); group.scan((msgID, handleStr, v) -> { ReceiptHandle handle = ReceiptHandle.decode(v.getReceiptHandle()); @@ -160,6 +172,18 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { return clientID + "%" + group; } + protected Pair parseKey(String key) { + String[] strs = key.split("%"); + if (strs.length < 2) { + return null; + } + return Pair.of(strs[0], strs[1]); + } + + protected boolean clientIsOffline(String clientID, String group) { + return this.messagingProcessor.findConsumerChannel(createContext("JudgeClientOnline"), group, clientID) == null; + } + public void addReceiptHandle(String clientID, String group, String msgID, String receiptHandle, MessageReceiptHandle messageReceiptHandle) { this.addReceiptHandle(buildKey(clientID, group), msgID, receiptHandle, messageReceiptHandle); @@ -212,26 +236,23 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { return res.get(); } - public void clearGroup(String key) { + protected void clearGroup(String key) { if (key == null) { return; } ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); ProxyContext context = createContext("ClearGroup"); - receiptHandleGroupMap.computeIfPresent(key, (k, v) -> { - v.scan((msgID, handle, value0) -> { - ReceiptHandle receiptHandle = ReceiptHandle.decode(value0.getReceiptHandle()); - messagingProcessor.changeInvisibleTime( - context, - receiptHandle, - value0.getMessageId(), - value0.getGroup(), - value0.getTopic(), - proxyConfig.getInvisibleTimeMillisWhenClear() - ); - }); - return null; - } - ); + ReceiptHandleGroup handleGroup = receiptHandleGroupMap.remove(key); + handleGroup.scan((msgID, handle, messageReceiptHandle) -> { + ReceiptHandle receiptHandle = ReceiptHandle.decode(messageReceiptHandle.getReceiptHandle()); + messagingProcessor.changeInvisibleTime( + context, + receiptHandle, + messageReceiptHandle.getMessageId(), + messageReceiptHandle.getGroup(), + messageReceiptHandle.getTopic(), + proxyConfig.getInvisibleTimeMillisWhenClear() + ); + }); } } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index ae91ffce93..5d95ab3b58 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -56,11 +56,15 @@ public class RouteActivityTest extends BaseActivityTest { private static final String CLUSTER = "cluster"; private static final String TOPIC = "topic"; + private static final String GROUP = "group"; private static final String BROKER_NAME = "brokerName"; private static final Broker GRPC_BROKER = Broker.newBuilder().setName(BROKER_NAME).build(); private static final Resource GRPC_TOPIC = Resource.newBuilder() .setName(TOPIC) .build(); + private static final Resource GRPC_GROUP = Resource.newBuilder() + .setName(GROUP) + .build(); private static Endpoints grpcEndpoints = Endpoints.newBuilder() .setScheme(AddressScheme.IPv4) .addAddresses(Address.newBuilder().setHost("127.0.0.1").setPort(8080).build()) @@ -136,6 +140,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentRequest.newBuilder() .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) + .setGroup(GRPC_GROUP) .build() ).get(); @@ -152,6 +157,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentRequest.newBuilder() .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) + .setGroup(GRPC_GROUP) .build() ).get(); @@ -168,6 +174,7 @@ public class RouteActivityTest extends BaseActivityTest { QueryAssignmentRequest.newBuilder() .setEndpoints(grpcEndpoints) .setTopic(GRPC_TOPIC) + .setGroup(GRPC_GROUP) .build() ).get(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java index bc21990c9c..1f86332584 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessorTest.java @@ -18,6 +18,7 @@ package org.apache.rocketmq.proxy.processor; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; @@ -71,8 +72,9 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testAddReceiptHandle() { String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(channelId, GROUP, MSG_ID, receiptHandle, messageReceiptHandle); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(new SubscriptionGroupConfig()); + Mockito.when(messagingProcessor.findConsumerChannel(Mockito.any(), Mockito.eq(GROUP), Mockito.eq(channelId))).thenReturn(Mockito.mock(ClientChannelInfo.class)); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(1)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.eq(MESSAGE_ID), @@ -82,9 +84,10 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { @Test public void testRenewReceiptHandle() { String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, receiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(channelId, GROUP, MSG_ID, receiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); + Mockito.when(messagingProcessor.findConsumerChannel(Mockito.any(), Mockito.eq(GROUP), Mockito.eq(channelId))).thenReturn(Mockito.mock(ClientChannelInfo.class)); long newInvisibleTime = 2000L; ReceiptHandle newReceiptHandleClass = ReceiptHandle.builder() .startOffset(0L) @@ -131,7 +134,8 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { messageReceiptHandle = new MessageReceiptHandle(GROUP, TOPIC, QUEUE_ID, receiptHandle, MESSAGE_ID, OFFSET, RECONSUME_TIMES, newInvisibleTime); String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, newReceiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(channelId, GROUP, MSG_ID, newReceiptHandle, messageReceiptHandle); + Mockito.when(messagingProcessor.findConsumerChannel(Mockito.any(), Mockito.eq(GROUP), Mockito.eq(channelId))).thenReturn(Mockito.mock(ClientChannelInfo.class)); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); receiptHandleProcessor.scheduleRenewTask(); @@ -156,9 +160,10 @@ public class ReceiptHandleProcessorTest extends BaseProcessorTest { messageReceiptHandle = new MessageReceiptHandle(GROUP, TOPIC, QUEUE_ID, newReceiptHandle, MESSAGE_ID, OFFSET, RECONSUME_TIMES, INVISIBLE_TIME); String channelId = PROXY_CONTEXT.getVal(ContextVariable.CLIENT_ID); - receiptHandleProcessor.addReceiptHandle(channelId, MSG_ID, newReceiptHandle, messageReceiptHandle); + receiptHandleProcessor.addReceiptHandle(channelId, GROUP, MSG_ID, newReceiptHandle, messageReceiptHandle); SubscriptionGroupConfig groupConfig = new SubscriptionGroupConfig(); Mockito.when(metadataService.getSubscriptionGroupConfig(Mockito.eq(GROUP))).thenReturn(groupConfig); + Mockito.when(messagingProcessor.findConsumerChannel(Mockito.any(), Mockito.eq(GROUP), Mockito.eq(channelId))).thenReturn(Mockito.mock(ClientChannelInfo.class)); receiptHandleProcessor.scheduleRenewTask(); Mockito.verify(messagingProcessor, Mockito.timeout(1000).times(0)) .changeInvisibleTime(Mockito.any(ProxyContext.class), Mockito.any(ReceiptHandle.class), Mockito.anyString(), From cb42639c57ab8916420e55fdc4bcb98c47ac825e Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 30 Jun 2022 20:21:42 +0800 Subject: [PATCH 287/338] [ISSUE #3949] validate consumer group in telemetry command --- .../org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 8bacbc6f85..5c5d72c7de 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -274,6 +274,7 @@ public class ClientActivity extends AbstractMessingActivity { } } if (settings.hasSubscription()) { + validateConsumerGroup(settings.getSubscription().getGroup()); String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); GrpcClientChannel consumerChannel = this.grpcChannelManager.createChannel(ctx, groupName, clientId); consumerChannel.setClientObserver(responseObserver); From 27c4ff948a21e0fe3d35fde3aa3fe8869c96bf98 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 5 Jul 2022 15:15:22 +0800 Subject: [PATCH 288/338] [ISSUE #3949] fix cannot remove handle after renew --- .../common/consumer/ReceiptHandle.java | 9 ----- .../proxy/grpc/v2/common/GrpcConverter.java | 7 ++-- .../ReceiveMessageResponseStreamWriter.java | 5 +-- .../proxy/processor/ConsumerProcessor.java | 36 +++++++++++++++++-- .../proxy/processor/BaseProcessorTest.java | 9 +++++ .../processor/ConsumerProcessorTest.java | 4 +-- .../processor/ProducerProcessorTest.java | 3 +- 7 files changed, 51 insertions(+), 22 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java index 8d5d62c1a9..392a3ae339 100644 --- a/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java +++ b/common/src/main/java/org/apache/rocketmq/common/consumer/ReceiptHandle.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.List; import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.message.MessageConst; -import org.apache.rocketmq.common.message.MessageExt; public class ReceiptHandle { private static final String SEPARATOR = MessageConst.KEY_SEPARATOR; @@ -45,14 +44,6 @@ public class ReceiptHandle { + commitLogOffset; } - public static ReceiptHandle create(MessageExt messageExt) { - String ckInfo = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); - if (ckInfo == null) { - return null; - } - return decode(ckInfo + SEPARATOR + messageExt.getCommitLogOffset()); - } - public boolean isExpired() { return nextVisibleTime <= System.currentTimeMillis(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 19786a32b1..6fdb85566c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -36,7 +36,6 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.filter.ExpressionType; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; @@ -204,9 +203,9 @@ public class GrpcConverter { } // receipt_handle && invisible_period - ReceiptHandle receiptHandle = ReceiptHandle.create(messageExt); - if (receiptHandle != null) { - systemPropertiesBuilder.setReceiptHandle(receiptHandle.encode()); + String handle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (handle != null) { + systemPropertiesBuilder.setReceiptHandle(handle); } // partition_id diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java index 054e9d23e0..aac818d870 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -29,6 +29,7 @@ import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; @@ -111,14 +112,14 @@ public class ReceiveMessageResponseStreamWriter { protected void processThrowableWhenWriteMessage(Throwable throwable, ProxyContext ctx, ReceiveMessageRequest request, MessageExt messageExt) { - ReceiptHandle handle = ReceiptHandle.create(messageExt); + String handle = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); if (handle == null) { return; } this.messagingProcessor.changeInvisibleTime( ctx, - handle, + ReceiptHandle.decode(handle), messageExt.getMsgId(), GrpcConverter.wrapResourceWithNamespace(request.getGroup()), GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), 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 30df54b7c1..07ef35089b 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 @@ -26,12 +26,15 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.PopResult; import org.apache.rocketmq.client.consumer.PopStatus; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.consumer.ReceiptHandle; +import org.apache.rocketmq.common.message.MessageAccessor; +import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody; @@ -119,13 +122,21 @@ public class ConsumerProcessor extends AbstractProcessor { List messageExtList = new ArrayList<>(); for (MessageExt messageExt : popResult.getMsgFoundList()) { try { + String handleString = createHandle(messageExt.getProperty(MessageConst.PROPERTY_POP_CK), messageExt.getCommitLogOffset()); + if (handleString == null) { + log.error("[BUG] pop message from broker but handle is empty. requestHeader:{}, msg:{}", requestHeader, messageExt); + messageExtList.add(messageExt); + continue; + } + MessageAccessor.putProperty(messageExt, MessageConst.PROPERTY_POP_CK, handleString); + PopMessageResultFilter.FilterResult filterResult = popMessageResultFilter.filterMessage(ctx, consumerGroup, subscriptionData, messageExt); switch (filterResult) { case NO_MATCH: this.messagingProcessor.ackMessage( ctx, - ReceiptHandle.create(messageExt), + ReceiptHandle.decode(handleString), messageExt.getMsgId(), consumerGroup, topic, @@ -134,7 +145,7 @@ public class ConsumerProcessor extends AbstractProcessor { case TO_DLQ: this.messagingProcessor.forwardMessageToDeadLetterQueue( ctx, - ReceiptHandle.create(messageExt), + ReceiptHandle.decode(handleString), messageExt.getMsgId(), consumerGroup, topic, @@ -204,19 +215,38 @@ public class ConsumerProcessor extends AbstractProcessor { changeInvisibleTimeRequestHeader.setExtraInfo(handle.getReceiptHandle()); changeInvisibleTimeRequestHeader.setOffset(handle.getOffset()); changeInvisibleTimeRequestHeader.setInvisibleTime(invisibleTime); + long commitLogOffset = handle.getCommitLogOffset(); future = this.serviceManager.getMessageService().changeInvisibleTime( ctx, handle, messageId, changeInvisibleTimeRequestHeader, - timeoutMillis); + timeoutMillis) + .thenApplyAsync(ackResult -> { + if (StringUtils.isNotBlank(ackResult.getExtraInfo())) { + AckResult result = new AckResult(); + result.setStatus(ackResult.getStatus()); + result.setPopTime(result.getPopTime()); + result.setExtraInfo(createHandle(ackResult.getExtraInfo(), commitLogOffset)); + return result; + } else { + return ackResult; + } + }, this.executor); } catch (Throwable t) { future.completeExceptionally(t); } return FutureUtils.addExecutor(future, this.executor); } + protected String createHandle(String handleString, long commitLogOffset) { + if (handleString == null) { + return null; + } + return handleString + MessageConst.KEY_SEPARATOR + commitLogOffset; + } + public CompletableFuture pullMessage(ProxyContext ctx, MessageQueue messageQueue, String consumerGroup, long queueOffset, int maxMsgNums, int sysFlag, long commitOffset, long suspendTimeoutMillis, SubscriptionData subscriptionData, long timeoutMillis) { 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 58d7dce874..a5c1d28365 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 @@ -22,6 +22,7 @@ import java.util.Random; import java.util.UUID; import org.apache.rocketmq.broker.client.ConsumerManager; import org.apache.rocketmq.broker.client.ProducerManager; +import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; @@ -103,4 +104,12 @@ public class BaseProcessorTest extends InitConfigAndLoggerTest { RANDOM.nextInt(Integer.MAX_VALUE), topic, "mockBroker", RANDOM.nextInt(Integer.MAX_VALUE), RANDOM.nextInt(Integer.MAX_VALUE))); return messageExt; } + + protected static ReceiptHandle create(MessageExt messageExt) { + String ckInfo = messageExt.getProperty(MessageConst.PROPERTY_POP_CK); + if (ckInfo == null) { + return null; + } + return ReceiptHandle.decode(ckInfo + MessageConst.KEY_SEPARATOR + messageExt.getCommitLogOffset()); + } } 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 a36a596e38..dc7e969e78 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 @@ -135,7 +135,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { @Test public void testAckMessage() throws Throwable { - ReceiptHandle handle = ReceiptHandle.create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); + ReceiptHandle handle = create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); assertNotNull(handle); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(AckMessageRequestHeader.class); @@ -155,7 +155,7 @@ public class ConsumerProcessorTest extends BaseProcessorTest { @Test public void testChangeInvisibleTime() throws Throwable { - ReceiptHandle handle = ReceiptHandle.create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); + ReceiptHandle handle = create(createMessageExt(MixAll.RETRY_GROUP_TOPIC_PREFIX + TOPIC, "", 0, 3000)); assertNotNull(handle); ArgumentCaptor requestHeaderArgumentCaptor = ArgumentCaptor.forClass(ChangeInvisibleTimeRequestHeader.class); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java index 6a1972c197..690775e7c4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/processor/ProducerProcessorTest.java @@ -27,7 +27,6 @@ import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.KeyBuilder; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.attribute.TopicMessageType; -import org.apache.rocketmq.common.consumer.ReceiptHandle; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageClientIDSetter; @@ -187,7 +186,7 @@ public class ProducerProcessorTest extends BaseProcessorTest { MessageExt messageExt = createMessageExt(KeyBuilder.buildPopRetryTopic(TOPIC, CONSUMER_GROUP), "", 16, 3000); RemotingCommand remotingCommand = this.producerProcessor.forwardMessageToDeadLetterQueue( createContext(), - ReceiptHandle.create(messageExt), + create(messageExt), messageExt.getMsgId(), CONSUMER_GROUP, TOPIC, From ddaf054d6507f8977e2c4bc4c3a1580334d9a1c6 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 6 Jul 2022 10:47:22 +0800 Subject: [PATCH 289/338] [ISSUE #3949] add client version to proxy context. --- .../apache/rocketmq/proxy/common/ContextVariable.java | 1 + .../org/apache/rocketmq/proxy/common/ProxyContext.java | 9 +++++++++ .../rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java | 1 + 3 files changed, 11 insertions(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java index 2f3c470c8c..dcfc529090 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ContextVariable.java @@ -22,6 +22,7 @@ public class ContextVariable { public static final String LOCAL_ADDRESS = "local-address"; public static final String CLIENT_ID = "client-id"; public static final String LANGUAGE = "language"; + public static final String CLIENT_VERSION = "client-version"; public static final String REMAINING_MS = "remaining-ms"; public static final String ACTION = "action"; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java index 22386979a2..6a35993fec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/common/ProxyContext.java @@ -85,6 +85,15 @@ public class ProxyContext { return this.getVal(ContextVariable.LANGUAGE); } + public ProxyContext setClientVersion(String clientVersion) { + this.withVal(ContextVariable.CLIENT_VERSION, clientVersion); + return this; + } + + public String getClientVersion() { + return this.getVal(ContextVariable.CLIENT_VERSION); + } + public ProxyContext setRemainingMs(Long remainingMs) { this.withVal(ContextVariable.REMAINING_MS, remainingMs); return this; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 218099f178..2840261773 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -172,6 +172,7 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ .setRemoteAddress(getDefaultStringMetadataInfo(headers, InterceptorConstants.REMOTE_ADDRESS)) .setClientID(getDefaultStringMetadataInfo(headers, InterceptorConstants.CLIENT_ID)) .setLanguage(getDefaultStringMetadataInfo(headers, InterceptorConstants.LANGUAGE)) + .setClientVersion(getDefaultStringMetadataInfo(headers, InterceptorConstants.CLIENT_VERSION)) .setAction(getDefaultStringMetadataInfo(headers, InterceptorConstants.RPC_NAME)); if (ctx.getDeadline() != null) { context.setRemainingMs(ctx.getDeadline().timeRemaining(TimeUnit.MILLISECONDS)); From 3fa4416114dcec7f4408afb8de3ca96894c04397 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 5 Jul 2022 16:48:10 +0800 Subject: [PATCH 290/338] [ISSUE #3949] use singleton for ResponseBuilder; check channel in recv and use handle saved in ack for autoRenew --- .../grpc/v2/GrpcMessagingApplication.java | 4 +-- .../proxy/grpc/v2/client/ClientActivity.java | 14 ++++---- .../grpc/v2/common/GrpcProxyException.java | 6 +++- .../proxy/grpc/v2/common/ResponseBuilder.java | 36 +++++++++++++------ .../grpc/v2/consumer/AckMessageActivity.java | 24 +++++++------ .../ChangeInvisibleDurationActivity.java | 4 +-- .../v2/consumer/ReceiveMessageActivity.java | 14 ++++---- .../ReceiveMessageResponseStreamWriter.java | 14 ++++---- .../producer/ForwardMessageToDLQActivity.java | 2 +- .../grpc/v2/producer/SendMessageActivity.java | 16 ++++----- .../proxy/grpc/v2/route/RouteActivity.java | 6 ++-- .../transaction/EndTransactionActivity.java | 2 +- .../grpc/v2/GrpcMessagingApplicationTest.java | 2 +- .../grpc/v2/client/ClientActivityTest.java | 4 +-- .../grpc/v2/route/RouteActivityTest.java | 2 +- .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 8 ++--- 16 files changed, 88 insertions(+), 70 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 2840261773..9c1674112e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -140,11 +140,11 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ } protected Status flowLimitStatus() { - return ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "flow limit"); + return ResponseBuilder.getInstance().buildStatus(Code.TOO_MANY_REQUESTS, "flow limit"); } protected Status convertExceptionToStatus(Throwable t) { - return ResponseBuilder.buildStatus(t); + return ResponseBuilder.getInstance().buildStatus(t); } protected void addExecutor(ExecutorService executor, ProxyContext context, V request, Runnable runnable, diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 5c5d72c7de..34bd405446 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -98,7 +98,7 @@ public class ClientActivity extends AbstractMessingActivity { Settings clientSettings = grpcClientSettingsManager.getClientSettings(ctx); if (clientSettings == null) { future.complete(HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, "cannot find client settings for this client")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, "cannot find client settings for this client")) .build()); return future; } @@ -134,13 +134,13 @@ public class ClientActivity extends AbstractMessingActivity { } default: { future.complete(HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) .build()); return future; } } future.complete(HeartbeatResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); return future; } catch (Throwable t) { @@ -182,12 +182,12 @@ public class ClientActivity extends AbstractMessingActivity { break; default: future.complete(NotifyClientTerminationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.UNRECOGNIZED_CLIENT_TYPE, clientSettings.getClientType().name())) .build()); return future; } future.complete(NotifyClientTerminationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); } catch (Throwable t) { future.completeExceptionally(t); @@ -233,7 +233,7 @@ public class ClientActivity extends AbstractMessingActivity { } protected TelemetryCommand convertToTelemetryCommand(Throwable t) { - return TelemetryCommand.newBuilder().setStatus(ResponseBuilder.buildStatus(t)).build(); + return TelemetryCommand.newBuilder().setStatus(ResponseBuilder.getInstance().buildStatus(t)).build(); } protected TelemetryCommand processClientSettings(ProxyContext ctx, TelemetryCommand request, @@ -283,7 +283,7 @@ public class ClientActivity extends AbstractMessingActivity { grpcClientSettingsManager.updateClientSettings(clientId, request.getSettings()); settings = grpcClientSettingsManager.getClientSettings(ctx); return TelemetryCommand.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .setSettings(settings) .build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java index aa2fd45044..74e499b4d7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcProxyException.java @@ -27,7 +27,7 @@ public class GrpcProxyException extends RuntimeException { private ProxyException proxyException; private Code code; - public static final Map CODE_MAPPING = new ConcurrentHashMap<>(); + protected static final Map CODE_MAPPING = new ConcurrentHashMap<>(); static { CODE_MAPPING.put(ProxyExceptionCode.INVALID_BROKER_NAME, Code.BAD_REQUEST); @@ -61,4 +61,8 @@ public class GrpcProxyException extends RuntimeException { } return Code.INTERNAL_SERVER_ERROR; } + + public ProxyException getProxyException() { + return proxyException; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java index 799e9c4185..08fa124be7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseBuilder.java @@ -36,7 +36,10 @@ import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; public class ResponseBuilder { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - public static final Map RESPONSE_CODE_MAPPING = new ConcurrentHashMap<>(); + protected static final Map RESPONSE_CODE_MAPPING = new ConcurrentHashMap<>(); + + protected static final Object INSTANCE_CREATE_LOCK = new Object(); + protected static volatile ResponseBuilder instance; static { RESPONSE_CODE_MAPPING.put(ResponseCode.SUCCESS, Code.OK); @@ -46,7 +49,18 @@ public class ResponseBuilder { RESPONSE_CODE_MAPPING.put(ClientErrorCode.ACCESS_BROKER_TIMEOUT, Code.PROXY_TIMEOUT); } - public static Status buildStatus(Throwable t) { + public static ResponseBuilder getInstance() { + if (instance == null) { + synchronized (INSTANCE_CREATE_LOCK) { + if (instance == null) { + instance = new ResponseBuilder(); + } + } + } + return instance; + } + + public Status buildStatus(Throwable t) { t = ExceptionUtils.getRealException(t); if (t instanceof ProxyException) { @@ -54,35 +68,35 @@ public class ResponseBuilder { } if (t instanceof GrpcProxyException) { GrpcProxyException grpcProxyException = (GrpcProxyException) t; - return ResponseBuilder.buildStatus(grpcProxyException.getCode(), grpcProxyException.getMessage()); + return buildStatus(grpcProxyException.getCode(), grpcProxyException.getMessage()); } if (TopicRouteHelper.isTopicNotExistError(t)) { - return ResponseBuilder.buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage()); + return buildStatus(Code.TOPIC_NOT_FOUND, t.getMessage()); } if (t instanceof MQBrokerException) { MQBrokerException mqBrokerException = (MQBrokerException) t; - return ResponseBuilder.buildStatus(buildCode(mqBrokerException.getResponseCode()), mqBrokerException.getErrorMessage()); + return buildStatus(buildCode(mqBrokerException.getResponseCode()), mqBrokerException.getErrorMessage()); } if (t instanceof MQClientException) { MQClientException mqClientException = (MQClientException) t; - return ResponseBuilder.buildStatus(buildCode(mqClientException.getResponseCode()), mqClientException.getErrorMessage()); + return buildStatus(buildCode(mqClientException.getResponseCode()), mqClientException.getErrorMessage()); } if (t instanceof RemotingTimeoutException) { - return ResponseBuilder.buildStatus(Code.PROXY_TIMEOUT, t.getMessage()); + return buildStatus(Code.PROXY_TIMEOUT, t.getMessage()); } log.error("internal server error", t); - return ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, ExceptionUtils.getErrorDetailMessage(t)); + return buildStatus(Code.INTERNAL_SERVER_ERROR, ExceptionUtils.getErrorDetailMessage(t)); } - public static Status buildStatus(Code code, String message) { + public Status buildStatus(Code code, String message) { return Status.newBuilder() .setCode(code) .setMessage(message) .build(); } - public static Status buildStatus(int remotingResponseCode, String remark) { + public Status buildStatus(int remotingResponseCode, String remark) { String message = remark; if (message == null) { message = String.valueOf(remotingResponseCode); @@ -93,7 +107,7 @@ public class ResponseBuilder { .build(); } - public static Code buildCode(int remotingResponseCode) { + public Code buildCode(int remotingResponseCode) { return RESPONSE_CODE_MAPPING.getOrDefault(remotingResponseCode, Code.INTERNAL_SERVER_ERROR); } } 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 2e19a2c329..1a373bf736 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 @@ -29,6 +29,7 @@ import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; 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.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; @@ -74,12 +75,12 @@ public class AckMessageActivity extends AbstractMessingActivity { AckMessageResponse.Builder responseBuilder = AckMessageResponse.newBuilder() .addAllEntries(entryList); if (responseCodes.size() > 1) { - responseBuilder.setStatus(ResponseBuilder.buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name())); + 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.buildStatus(code, code.name())); + responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(code, code.name())); } else { - responseBuilder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message result is empty")); + responseBuilder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack message result is empty")); } future.complete(responseBuilder.build()); }); @@ -94,19 +95,20 @@ public class AckMessageActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); try { - ReceiptHandle receiptHandle = ReceiptHandle.decode(ackMessageEntry.getReceiptHandle()); + String handleString = ackMessageEntry.getReceiptHandle(); String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + MessageReceiptHandle messageReceiptHandle = receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle()); + if (messageReceiptHandle != null) { + handleString = messageReceiptHandle.getReceiptHandle(); + } CompletableFuture ackResultFuture = this.messagingProcessor.ackMessage( ctx, - receiptHandle, + ReceiptHandle.decode(handleString), ackMessageEntry.getMessageId(), group, GrpcConverter.wrapResourceWithNamespace(request.getTopic())); ackResultFuture.thenAccept(result -> { - if (AckStatus.OK.equals(result.getStatus())) { - receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle()); - } future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); }).exceptionally(t -> { future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, t)); @@ -120,7 +122,7 @@ public class AckMessageActivity extends AbstractMessingActivity { protected AckMessageResultEntry convertToAckMessageResultEntry(ProxyContext ctx, AckMessageEntry ackMessageEntry, Throwable throwable) { return AckMessageResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(throwable)) + .setStatus(ResponseBuilder.getInstance().buildStatus(throwable)) .setMessageId(ackMessageEntry.getMessageId()) .setReceiptHandle(ackMessageEntry.getReceiptHandle()) .build(); @@ -132,13 +134,13 @@ public class AckMessageActivity extends AbstractMessingActivity { return AckMessageResultEntry.newBuilder() .setMessageId(ackMessageEntry.getMessageId()) .setReceiptHandle(ackMessageEntry.getReceiptHandle()) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build(); } return AckMessageResultEntry.newBuilder() .setMessageId(ackMessageEntry.getMessageId()) .setReceiptHandle(ackMessageEntry.getReceiptHandle()) - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "ack failed: status is abnormal")) .build(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index bfee5c3134..fe0844ace4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -76,12 +76,12 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { ChangeInvisibleDurationRequest request, AckResult ackResult) { if (AckStatus.OK.equals(ackResult.getStatus())) { return ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .setReceiptHandle(ackResult.getExtraInfo()) .build(); } return ChangeInvisibleDurationResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "changeInvisibleDuration failed: status is abnormal")) .build(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 8c4dcb78d9..7da3b39cce 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -22,6 +22,7 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; +import com.google.common.base.Preconditions; import com.google.protobuf.util.Durations; import io.grpc.stub.StreamObserver; import java.time.Duration; @@ -71,24 +72,23 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { timeRemaining = Duration.ofSeconds(20).toMillis(); } long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); - if (pollTime <= 0) { - pollTime = timeRemaining; - } if (pollTime <= 0) { writer.writeAndComplete(ctx, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); return; } + validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); + String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + long actualInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { + Preconditions.checkNotNull(this.messagingProcessor.findConsumerChannel(ctx, group, ctx.getClientID()), + "cannot find channel in consumerManager"); actualInvisibleTime = proxyConfig.getRenewSliceTimeMillis(); } - validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); - - String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); FilterExpression filterExpression = request.getFilterExpression(); SubscriptionData subscriptionData; try { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java index aac818d870..45a0156698 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -61,11 +61,11 @@ public class ReceiveMessageResponseStreamWriter { case FOUND: if (messageFoundList.isEmpty()) { streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no match message")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.MESSAGE_NOT_FOUND, "no match message")) .build()); } else { streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); Iterator messageIterator = messageFoundList.iterator(); while (messageIterator.hasNext()) { @@ -86,20 +86,20 @@ public class ReceiveMessageResponseStreamWriter { break; case POLLING_FULL: streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.TOO_MANY_REQUESTS, "polling full")) .build()); break; case NO_NEW_MSG: case POLLING_NOT_FOUND: default: streamObserver.onNext(ReceiveMessageResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.MESSAGE_NOT_FOUND, "no new message")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.MESSAGE_NOT_FOUND, "no new message")) .build()); break; } } catch (Throwable t) { writeResponseWithErrorIgnore( - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(t)).build()); + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.getInstance().buildStatus(t)).build()); } finally { onComplete(); } @@ -129,13 +129,13 @@ public class ReceiveMessageResponseStreamWriter { public void writeAndComplete(ProxyContext ctx, Code code, String message) { writeResponseWithErrorIgnore( - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(code, message)).build()); + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.getInstance().buildStatus(code, message)).build()); onComplete(); } public void writeAndComplete(ProxyContext ctx, ReceiveMessageRequest request, Throwable throwable) { writeResponseWithErrorIgnore( - ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.buildStatus(throwable)).build()); + ReceiveMessageResponse.newBuilder().setStatus(ResponseBuilder.getInstance().buildStatus(throwable)).build()); onComplete(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java index ceb6dfbca2..6ae751b672 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -59,7 +59,7 @@ public class ForwardMessageToDLQActivity extends AbstractMessingActivity { protected ForwardMessageToDeadLetterQueueResponse convertToForwardMessageToDeadLetterQueueResponse(ProxyContext ctx, RemotingCommand result) { return ForwardMessageToDeadLetterQueueResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(result.getCode(), result.getRemark())) + .setStatus(ResponseBuilder.getInstance().buildStatus(result.getCode(), result.getRemark())) .build(); } } 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 f8a11fa3d6..8053c5d4de 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 @@ -283,22 +283,22 @@ public class SendMessageActivity extends AbstractMessingActivity { switch (result.getSendStatus()) { case FLUSH_DISK_TIMEOUT: resultEntry = SendResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.MASTER_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.MASTER_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) .build(); break; case FLUSH_SLAVE_TIMEOUT: resultEntry = SendResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.SLAVE_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.SLAVE_PERSISTENCE_TIMEOUT, "send message failed, sendStatus=" + result.getSendStatus())) .build(); break; case SLAVE_NOT_AVAILABLE: resultEntry = SendResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.HA_NOT_AVAILABLE, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.HA_NOT_AVAILABLE, "send message failed, sendStatus=" + result.getSendStatus())) .build(); break; case SEND_OK: resultEntry = SendResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .setOffset(result.getQueueOffset()) .setMessageId(StringUtils.defaultString(result.getMsgId())) .setTransactionId(StringUtils.defaultString(result.getTransactionId())) @@ -306,7 +306,7 @@ public class SendMessageActivity extends AbstractMessingActivity { break; default: resultEntry = SendResultEntry.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "send message failed, sendStatus=" + result.getSendStatus())) .build(); break; } @@ -314,12 +314,12 @@ public class SendMessageActivity extends AbstractMessingActivity { responseCodes.add(resultEntry.getStatus().getCode()); } if (responseCodes.size() > 1) { - builder.setStatus(ResponseBuilder.buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name())); + builder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.MULTIPLE_RESULTS, Code.MULTIPLE_RESULTS.name())); } else if (responseCodes.size() == 1) { Code code = responseCodes.stream().findAny().get(); - builder.setStatus(ResponseBuilder.buildStatus(code, code.name())); + builder.setStatus(ResponseBuilder.getInstance().buildStatus(code, code.name())); } else { - builder.setStatus(ResponseBuilder.buildStatus(Code.INTERNAL_SERVER_ERROR, "send status is empty")); + builder.setStatus(ResponseBuilder.getInstance().buildStatus(Code.INTERNAL_SERVER_ERROR, "send status is empty")); } return builder.build(); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index 4d12f78176..587eca41b3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -81,7 +81,7 @@ public class RouteActivity extends AbstractMessingActivity { } QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .addAllMessageQueues(messageQueueList) .build(); future.complete(response); @@ -129,12 +129,12 @@ public class RouteActivity extends AbstractMessingActivity { QueryAssignmentResponse response; if (assignments.isEmpty()) { response = QueryAssignmentResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.FORBIDDEN, "no readable queue")) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.FORBIDDEN, "no readable queue")) .build(); } else { response = QueryAssignmentResponse.newBuilder() .addAllAssignments(assignments) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build(); } future.complete(response); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index 9e12238c2f..64655e7829 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -68,7 +68,7 @@ public class EndTransactionActivity extends AbstractMessingActivity { transactionStatus, request.getSource().equals(TransactionSource.SOURCE_SERVER_CHECK)) .thenApply(r -> EndTransactionResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); } catch (Throwable t) { future.completeExceptionally(t); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 74a0815c4a..350f5802a3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -89,7 +89,7 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { Mockito.when(grpcMessingActivity.queryRoute(Mockito.any(ProxyContext.class), Mockito.eq(request))) .thenReturn(future); QueryRouteResponse response = QueryRouteResponse.newBuilder() - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .addMessageQueues(MessageQueue.getDefaultInstance()) .build(); grpcMessagingApplication.queryRoute(request, queryRouteResponseStreamObserver); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index 221fa05a7d..375841b9d3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -278,7 +278,7 @@ public class ClientActivityTest extends BaseActivityTest { .setThreadStackTrace(jstack) .setNonce(nonce) .build()) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); verify(runningInfoFutureMock, times(1)).complete(runningInfoArgumentCaptor.capture()); ProxyRelayResult result = runningInfoArgumentCaptor.getValue(); @@ -309,7 +309,7 @@ public class ClientActivityTest extends BaseActivityTest { .setVerifyMessageResult(VerifyMessageResult.newBuilder() .setNonce(nonce) .build()) - .setStatus(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())) + .setStatus(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())) .build()); verify(resultFutureMock, times(1)).complete(resultArgumentCaptor.capture()); ProxyRelayResult result = resultArgumentCaptor.getValue(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java index 5d95ab3b58..a8c79442b5 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivityTest.java @@ -124,7 +124,7 @@ public class RouteActivityTest extends BaseActivityTest { .build() ).get(); } catch (Throwable t) { - assertEquals(Code.TOPIC_NOT_FOUND, ResponseBuilder.buildStatus(t).getCode()); + assertEquals(Code.TOPIC_NOT_FOUND, ResponseBuilder.getInstance().buildStatus(t).getCode()); return; } fail(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 667f5a096e..434aceae96 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -92,7 +92,6 @@ import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer; import org.apache.rocketmq.client.consumer.PullResult; import org.apache.rocketmq.client.consumer.PullStatus; import org.apache.rocketmq.common.MixAll; -import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.attribute.TopicMessageType; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; @@ -107,7 +106,6 @@ import org.apache.rocketmq.test.util.MQRandomUtils; import org.apache.rocketmq.test.util.RandomUtils; import org.junit.Rule; -import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE; import static org.apache.rocketmq.common.message.MessageClientIDSetter.createUniqID; import static org.apache.rocketmq.proxy.config.ConfigurationManager.RMQ_PROXY_HOME; import static org.assertj.core.api.Assertions.assertThat; @@ -652,19 +650,19 @@ public class GrpcBaseIT extends BaseConf { } public void assertQueryRoute(QueryRouteResponse response, int messageQueueSize) { - assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())); assertThat(response.getMessageQueuesList().size()).isEqualTo(messageQueueSize); assertThat(response.getMessageQueues(0).getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } public void assertQueryAssignment(QueryAssignmentResponse response, int assignmentCount) { - assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())); assertThat(response.getAssignmentsCount()).isEqualTo(assignmentCount); assertThat(response.getAssignments(0).getMessageQueue().getBroker().getEndpoints().getAddresses(0).getPort()).isEqualTo(ConfigurationManager.getProxyConfig().getGrpcServerPort()); } public void assertSendMessage(SendMessageResponse response, String messageId) { - assertThat(response.getStatus()).isEqualTo(ResponseBuilder.buildStatus(Code.OK, Code.OK.name())); + assertThat(response.getStatus()).isEqualTo(ResponseBuilder.getInstance().buildStatus(Code.OK, Code.OK.name())); assertThat(response.getEntries(0).getMessageId()).isEqualTo(messageId); } From 87baf6da1bc220cc66d428e9a94cca72abb8bdf1 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 5 Jul 2022 16:53:37 +0800 Subject: [PATCH 291/338] [ISSUE #3949] use singleton for GrpcConverter and ResponseWriter --- .../grpc/v2/AbstractMessingActivity.java | 4 +-- .../grpc/v2/GrpcMessagingApplication.java | 4 +-- .../grpc/v2/channel/GrpcClientChannel.java | 6 ++-- .../proxy/grpc/v2/client/ClientActivity.java | 16 +++++------ .../v2/common/GrpcClientSettingsManager.java | 4 +-- .../proxy/grpc/v2/common/GrpcConverter.java | 28 ++++++++++++++----- .../proxy/grpc/v2/common/ResponseWriter.java | 20 +++++++++++-- .../grpc/v2/consumer/AckMessageActivity.java | 4 +-- .../ChangeInvisibleDurationActivity.java | 4 +-- .../v2/consumer/ReceiveMessageActivity.java | 6 ++-- .../ReceiveMessageResponseStreamWriter.java | 8 +++--- .../producer/ForwardMessageToDLQActivity.java | 4 +-- .../grpc/v2/producer/SendMessageActivity.java | 6 ++-- .../proxy/grpc/v2/route/RouteActivity.java | 4 +-- .../transaction/EndTransactionActivity.java | 2 +- .../grpc/v2/common/GrpcConverterTest.java | 2 +- 16 files changed, 75 insertions(+), 47 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 0949cafdc9..8b948bfc4e 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -61,7 +61,7 @@ public abstract class AbstractMessingActivity { } protected void validateTopic(Resource topic) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); if (StringUtils.isBlank(topicName)) { throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "topic name cannot be empty"); } @@ -82,7 +82,7 @@ public abstract class AbstractMessingActivity { } protected void validateConsumerGroup(Resource consumerGroup) { - String consumerGroupName = GrpcConverter.wrapResourceWithNamespace(consumerGroup); + String consumerGroupName = GrpcConverter.getInstance().wrapResourceWithNamespace(consumerGroup); if (StringUtils.isBlank(consumerGroupName)) { throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "consumer group cannot be empty"); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java index 9c1674112e..9c940dee76 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplication.java @@ -155,12 +155,12 @@ public class GrpcMessagingApplication extends MessagingServiceGrpc.MessagingServ protected void writeResponse(ProxyContext context, V request, T response, StreamObserver responseObserver, Throwable t, Function errorResponseCreator) { if (t != null) { - ResponseWriter.write( + ResponseWriter.getInstance().write( responseObserver, errorResponseCreator.apply(convertExceptionToStatus(t)) ); } else { - ResponseWriter.write(responseObserver, response); + ResponseWriter.getInstance().write(responseObserver, response); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 04d93af519..3f8dafaff8 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -133,8 +133,8 @@ public class GrpcClientChannel extends ProxyChannel { this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(transactionData.getTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverter.buildMessage(messageExt)) - .setMessageQueue(GrpcConverter.buildMessageQueue(messageExt, transactionData.getBrokerName())) + .setOrphanedTransactionalMessage(GrpcConverter.getInstance().buildMessage(messageExt)) + .setMessageQueue(GrpcConverter.getInstance().buildMessageQueue(messageExt, transactionData.getBrokerName())) .build()) .build()); responseFuture.complete(null); @@ -168,7 +168,7 @@ public class GrpcClientChannel extends ProxyChannel { this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() .setVerifyMessageCommand(VerifyMessageCommand.newBuilder() .setNonce(this.grpcChannelManager.addResponseFuture(responseFuture)) - .setMessage(GrpcConverter.buildMessage(messageExt)) + .setMessage(GrpcConverter.getInstance().buildMessage(messageExt)) .build()) .build()); return CompletableFuture.completedFuture(null); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 34bd405446..9b52874184 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -105,7 +105,7 @@ public class ClientActivity extends AbstractMessingActivity { switch (clientSettings.getClientType()) { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); // use topic name as producer group @@ -117,7 +117,7 @@ public class ClientActivity extends AbstractMessingActivity { case PUSH_CONSUMER: case SIMPLE_CONSUMER: { validateConsumerGroup(request.getGroup()); - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String consumerGroup = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -161,7 +161,7 @@ public class ClientActivity extends AbstractMessingActivity { switch (clientSettings.getClientType()) { case PRODUCER: for (Resource topic : clientSettings.getPublishing().getTopicsList()) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); // user topic name as producer group GrpcClientChannel channel = this.grpcChannelManager.removeChannel(topicName, clientId); if (channel != null) { @@ -173,7 +173,7 @@ public class ClientActivity extends AbstractMessingActivity { case PUSH_CONSUMER: case SIMPLE_CONSUMER: validateConsumerGroup(request.getGroup()); - String consumerGroup = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String consumerGroup = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); GrpcClientChannel channel = this.grpcChannelManager.removeChannel(consumerGroup, clientId); if (channel != null) { ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); @@ -268,14 +268,14 @@ public class ClientActivity extends AbstractMessingActivity { if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { validateTopic(topic); - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); GrpcClientChannel producerChannel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { validateConsumerGroup(settings.getSubscription().getGroup()); - String groupName = GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup()); + String groupName = GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup()); GrpcClientChannel consumerChannel = this.grpcChannelManager.createChannel(ctx, groupName, clientId); consumerChannel.setClientObserver(responseObserver); } @@ -357,7 +357,7 @@ public class ClientActivity extends AbstractMessingActivity { protected Set buildSubscriptionDataSet(List subscriptionEntryList) { Set subscriptionDataSet = new HashSet<>(); for (SubscriptionEntry sub : subscriptionEntryList) { - String topicName = GrpcConverter.wrapResourceWithNamespace(sub.getTopic()); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(sub.getTopic()); FilterExpression filterExpression = sub.getExpression(); subscriptionDataSet.add(buildSubscriptionData(topicName, filterExpression)); } @@ -366,7 +366,7 @@ public class ClientActivity extends AbstractMessingActivity { protected SubscriptionData buildSubscriptionData(String topicName, FilterExpression filterExpression) { String expression = filterExpression.getExpression(); - String expressionType = GrpcConverter.buildExpressionType(filterExpression.getType()); + String expressionType = GrpcConverter.getInstance().buildExpressionType(filterExpression.getType()); try { return FilterAPI.build(topicName, expression, expressionType); } catch (Exception e) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index 5e36c8d13f..1ae6b9e07c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -79,7 +79,7 @@ public class GrpcClientSettingsManager { } if (settings.hasSubscription()) { settings = mergeSubscriptionData(ctx, settings, - GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup())); + GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup())); } return settings; } @@ -154,6 +154,6 @@ public class GrpcClientSettingsManager { return null; } return mergeSubscriptionData(ctx, settings, - GrpcConverter.wrapResourceWithNamespace(settings.getSubscription().getGroup())); + GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup())); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java index 6fdb85566c..cc5a60ca6d 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverter.java @@ -49,11 +49,25 @@ import org.apache.rocketmq.remoting.common.RemotingUtil; public class GrpcConverter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - public static String wrapResourceWithNamespace(Resource resource) { + protected static final Object INSTANCE_CREATE_LOCK = new Object(); + protected static volatile GrpcConverter instance; + + public static GrpcConverter getInstance() { + if (instance == null) { + synchronized (INSTANCE_CREATE_LOCK) { + if (instance == null) { + instance = new GrpcConverter(); + } + } + } + return instance; + } + + public String wrapResourceWithNamespace(Resource resource) { return NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); } - public static MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { + public MessageQueue buildMessageQueue(MessageExt messageExt, String brokerName) { Broker broker = Broker.getDefaultInstance(); if (!StringUtils.isEmpty(brokerName)) { broker = Broker.newBuilder() @@ -71,7 +85,7 @@ public class GrpcConverter { .build(); } - public static String buildExpressionType(FilterType filterType) { + public String buildExpressionType(FilterType filterType) { switch (filterType) { case SQL: return ExpressionType.SQL92; @@ -81,7 +95,7 @@ public class GrpcConverter { } } - public static Message buildMessage(MessageExt messageExt) { + public Message buildMessage(MessageExt messageExt) { Map userProperties = buildUserAttributes(messageExt); SystemProperties systemProperties = buildSystemProperties(messageExt); Resource topic = buildResource(messageExt.getTopic()); @@ -94,7 +108,7 @@ public class GrpcConverter { .build(); } - protected static Map buildUserAttributes(MessageExt messageExt) { + protected Map buildUserAttributes(MessageExt messageExt) { Map userAttributes = new HashMap<>(); Map properties = messageExt.getProperties(); @@ -107,7 +121,7 @@ public class GrpcConverter { return userAttributes; } - protected static SystemProperties buildSystemProperties(MessageExt messageExt) { + protected SystemProperties buildSystemProperties(MessageExt messageExt) { SystemProperties.Builder systemPropertiesBuilder = SystemProperties.newBuilder(); // tag @@ -226,7 +240,7 @@ public class GrpcConverter { return systemPropertiesBuilder.build(); } - public static Resource buildResource(String resourceNameWithNamespace) { + public Resource buildResource(String resourceNameWithNamespace) { return Resource.newBuilder() .setResourceNamespace(NamespaceUtil.getNamespaceFromResource(resourceNameWithNamespace)) .setName(NamespaceUtil.withoutNamespace(resourceNameWithNamespace)) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java index dd2be5f872..43ddf99992 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/ResponseWriter.java @@ -28,13 +28,27 @@ import org.apache.rocketmq.logging.InternalLoggerFactory; public class ResponseWriter { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - public static void write(StreamObserver observer, final T response) { + protected static final Object INSTANCE_CREATE_LOCK = new Object(); + protected static volatile ResponseWriter instance; + + public static ResponseWriter getInstance() { + if (instance == null) { + synchronized (INSTANCE_CREATE_LOCK) { + if (instance == null) { + instance = new ResponseWriter(); + } + } + } + return instance; + } + + public void write(StreamObserver observer, final T response) { if (writeResponse(observer, response)) { observer.onCompleted(); } } - public static boolean writeResponse(StreamObserver observer, final T response) { + public boolean writeResponse(StreamObserver observer, final T response) { if (null == response) { return false; } @@ -55,7 +69,7 @@ public class ResponseWriter { return true; } - public static boolean isCancelled(StreamObserver observer) { + public boolean isCancelled(StreamObserver observer) { if (observer instanceof ServerCallStreamObserver) { final ServerCallStreamObserver serverCallStreamObserver = (ServerCallStreamObserver) observer; return serverCallStreamObserver.isCancelled(); 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 1a373bf736..5f4c85af7c 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 @@ -97,7 +97,7 @@ public class AckMessageActivity extends AbstractMessingActivity { try { String handleString = ackMessageEntry.getReceiptHandle(); - String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); MessageReceiptHandle messageReceiptHandle = receiptHandleProcessor.removeReceiptHandle(ctx.getClientID(), group, ackMessageEntry.getMessageId(), ackMessageEntry.getReceiptHandle()); if (messageReceiptHandle != null) { handleString = messageReceiptHandle.getReceiptHandle(); @@ -107,7 +107,7 @@ public class AckMessageActivity extends AbstractMessingActivity { ReceiptHandle.decode(handleString), ackMessageEntry.getMessageId(), group, - GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic())); ackResultFuture.thenAccept(result -> { future.complete(convertToAckMessageResultEntry(ctx, ackMessageEntry, result)); }).exceptionally(t -> { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index fe0844ace4..71a71f2297 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -52,13 +52,13 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); - String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); return this.messagingProcessor.changeInvisibleTime( ctx, receiptHandle, request.getMessageId(), group, - GrpcConverter.wrapResourceWithNamespace(request.getTopic()), + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic()), Durations.toMillis(request.getInvisibleDuration()) ).thenApply(ackResult -> { if (AckStatus.OK.equals(ackResult.getStatus())) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 7da3b39cce..f301743829 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -78,8 +78,8 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { } validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); - String topic = GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()); - String group = GrpcConverter.wrapResourceWithNamespace(request.getGroup()); + String topic = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getMessageQueue().getTopic()); + String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); long actualInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); @@ -93,7 +93,7 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { SubscriptionData subscriptionData; try { subscriptionData = FilterAPI.build(topic, filterExpression.getExpression(), - GrpcConverter.buildExpressionType(filterExpression.getType())); + GrpcConverter.getInstance().buildExpressionType(filterExpression.getType())); } catch (Exception e) { writer.writeAndComplete(ctx, Code.ILLEGAL_FILTER_EXPRESSION, e.getMessage()); return; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java index 45a0156698..7faf1b41c6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageResponseStreamWriter.java @@ -106,7 +106,7 @@ public class ReceiveMessageResponseStreamWriter { } protected Message convertToMessage(MessageExt messageExt) { - return GrpcConverter.buildMessage(messageExt); + return GrpcConverter.getInstance().buildMessage(messageExt); } protected void processThrowableWhenWriteMessage(Throwable throwable, @@ -121,8 +121,8 @@ public class ReceiveMessageResponseStreamWriter { ctx, ReceiptHandle.decode(handle), messageExt.getMsgId(), - GrpcConverter.wrapResourceWithNamespace(request.getGroup()), - GrpcConverter.wrapResourceWithNamespace(request.getMessageQueue().getTopic()), + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getMessageQueue().getTopic()), NACK_INVISIBLE_TIME ); } @@ -141,7 +141,7 @@ public class ReceiveMessageResponseStreamWriter { protected void writeResponseWithErrorIgnore(ReceiveMessageResponse response) { try { - ResponseWriter.writeResponse(streamObserver, response); + ResponseWriter.getInstance().writeResponse(streamObserver, response); } catch (Exception e) { log.error("err when write receive message response", e); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java index 6ae751b672..6e1c85cff4 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/producer/ForwardMessageToDLQActivity.java @@ -47,8 +47,8 @@ public class ForwardMessageToDLQActivity extends AbstractMessingActivity { ctx, receiptHandle, request.getMessageId(), - GrpcConverter.wrapResourceWithNamespace(request.getGroup()), - GrpcConverter.wrapResourceWithNamespace(request.getTopic()) + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()), + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic()) ).thenApply(result -> convertToForwardMessageToDeadLetterQueueResponse(ctx, result)); } catch (Throwable t) { future.completeExceptionally(t); 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 8053c5d4de..11e5c0bfa8 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 @@ -78,7 +78,7 @@ public class SendMessageActivity extends AbstractMessingActivity { future = this.messagingProcessor.sendMessage( ctx, new SendMessageQueueSelector(request), - GrpcConverter.wrapResourceWithNamespace(topic), + GrpcConverter.getInstance().wrapResourceWithNamespace(topic), buildSysFlag(message), buildMessage(ctx, request.getMessagesList(), topic) ).thenApply(result -> convertToSendMessageResponse(ctx, request, result)); @@ -90,7 +90,7 @@ public class SendMessageActivity extends AbstractMessingActivity { protected List buildMessage(ProxyContext context, List protoMessageList, Resource topic) { - String topicName = GrpcConverter.wrapResourceWithNamespace(topic); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); List messageExtList = new ArrayList<>(); for (apache.rocketmq.v2.Message protoMessage : protoMessageList) { if (!protoMessage.getTopic().equals(topic)) { @@ -103,7 +103,7 @@ public class SendMessageActivity extends AbstractMessingActivity { } protected Message buildMessage(ProxyContext context, apache.rocketmq.v2.Message protoMessage, String producerGroup) { - String topicName = GrpcConverter.wrapResourceWithNamespace(protoMessage.getTopic()); + String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(protoMessage.getTopic()); validateMessageBodySize(protoMessage.getBody()); Message messageExt = new Message(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java index 587eca41b3..c5cf8a3e05 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/route/RouteActivity.java @@ -64,7 +64,7 @@ public class RouteActivity extends AbstractMessingActivity { ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( ctx, addressList, - GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic())); List messageQueueList = new ArrayList<>(); Map> brokerMap = buildBrokerMap(proxyTopicRouteData.getBrokerDatas()); @@ -102,7 +102,7 @@ public class RouteActivity extends AbstractMessingActivity { ProxyTopicRouteData proxyTopicRouteData = this.messagingProcessor.getTopicRouteDataForProxy( ctx, addressList, - GrpcConverter.wrapResourceWithNamespace(request.getTopic())); + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic())); List assignments = new ArrayList<>(); Map> brokerMap = buildBrokerMap(proxyTopicRouteData.getBrokerDatas()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java index 64655e7829..e65cf2eb4f 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/transaction/EndTransactionActivity.java @@ -64,7 +64,7 @@ public class EndTransactionActivity extends AbstractMessingActivity { ctx, request.getTransactionId(), request.getMessageId(), - GrpcConverter.wrapResourceWithNamespace(request.getTopic()), + GrpcConverter.getInstance().wrapResourceWithNamespace(request.getTopic()), transactionStatus, request.getSource().equals(TransactionSource.SOURCE_SERVER_CHECK)) .thenApply(r -> EndTransactionResponse.newBuilder() diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java index 9c743d8422..bc9b8a60b4 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcConverterTest.java @@ -33,7 +33,7 @@ public class GrpcConverterTest { messageExt.setQueueId(queueId); messageExt.setTopic(topic); - MessageQueue messageQueue = GrpcConverter.buildMessageQueue(messageExt, brokerName); + MessageQueue messageQueue = GrpcConverter.getInstance().buildMessageQueue(messageExt, brokerName); assertThat(messageQueue.getTopic().getName()).isEqualTo(topic); assertThat(messageQueue.getBroker().getName()).isEqualTo(brokerName); assertThat(messageQueue.getId()).isEqualTo(queueId); From fe2e23a3f0f08af266129d50d98980e48915f367 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 5 Jul 2022 17:19:31 +0800 Subject: [PATCH 292/338] [ISSUE #3949] add producer and consumer to manager in telemetryCommand --- .../proxy/grpc/v2/client/ClientActivity.java | 54 ++++++++++++------- .../v2/consumer/ReceiveMessageActivity.java | 2 - 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 9b52874184..bd8519279b 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -106,11 +106,7 @@ public class ClientActivity extends AbstractMessingActivity { case PRODUCER: { for (Resource topic : clientSettings.getPublishing().getTopicsList()) { String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); - GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - // use topic name as producer group - this.messagingProcessor.registerProducer(ctx, topicName, clientChannelInfo); - this.messagingProcessor.addTransactionSubscription(ctx, topicName, topicName); + this.registerProducer(ctx, topicName); } break; } @@ -118,18 +114,7 @@ public class ClientActivity extends AbstractMessingActivity { case SIMPLE_CONSUMER: { validateConsumerGroup(request.getGroup()); String consumerGroup = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); - GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); - - this.messagingProcessor.registerConsumer( - ctx, - consumerGroup, - clientChannelInfo, - this.buildConsumeType(clientSettings.getClientType()), - MessageModel.CLUSTERING, - ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, - this.buildSubscriptionDataSet(clientSettings.getSubscription().getSubscriptionsList()) - ); + this.registerConsumer(ctx, consumerGroup, clientSettings.getClientType(), clientSettings.getSubscription().getSubscriptionsList()); break; } default: { @@ -269,14 +254,14 @@ public class ClientActivity extends AbstractMessingActivity { for (Resource topic : settings.getPublishing().getTopicsList()) { validateTopic(topic); String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); - GrpcClientChannel producerChannel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); + GrpcClientChannel producerChannel = registerProducer(ctx, topicName); producerChannel.setClientObserver(responseObserver); } } if (settings.hasSubscription()) { validateConsumerGroup(settings.getSubscription().getGroup()); String groupName = GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup()); - GrpcClientChannel consumerChannel = this.grpcChannelManager.createChannel(ctx, groupName, clientId); + GrpcClientChannel consumerChannel = registerConsumer(ctx, groupName, settings.getClientType(), settings.getSubscription().getSubscriptionsList()); consumerChannel.setClientObserver(responseObserver); } @@ -288,6 +273,37 @@ public class ClientActivity extends AbstractMessingActivity { .build(); } + protected GrpcClientChannel registerProducer(ProxyContext ctx, String topicName) { + String clientId = ctx.getClientID(); + LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); + + GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); + // use topic name as producer group + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + this.messagingProcessor.registerProducer(ctx, topicName, clientChannelInfo); + this.messagingProcessor.addTransactionSubscription(ctx, topicName, topicName); + return channel; + } + + protected GrpcClientChannel registerConsumer(ProxyContext ctx, String consumerGroup, ClientType clientType, List subscriptionEntryList) { + String clientId = ctx.getClientID(); + LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); + + GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + + this.messagingProcessor.registerConsumer( + ctx, + consumerGroup, + clientChannelInfo, + this.buildConsumeType(clientType), + MessageModel.CLUSTERING, + ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, + this.buildSubscriptionDataSet(subscriptionEntryList) + ); + return channel; + } + protected void reportThreadStackTrace(ProxyContext ctx, Status status, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index f301743829..0a6a8af2ef 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -84,8 +84,6 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { long actualInvisibleTime = Durations.toMillis(request.getInvisibleDuration()); ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { - Preconditions.checkNotNull(this.messagingProcessor.findConsumerChannel(ctx, group, ctx.getClientID()), - "cannot find channel in consumerManager"); actualInvisibleTime = proxyConfig.getRenewSliceTimeMillis(); } From 9d4a136862c491f2af77c7369443e1259b5e9ed0 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 5 Jul 2022 18:55:36 +0800 Subject: [PATCH 293/338] [ISSUE #3949] for checkstyle --- .../rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 0a6a8af2ef..20326791a7 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -22,7 +22,6 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Settings; import apache.rocketmq.v2.Subscription; -import com.google.common.base.Preconditions; import com.google.protobuf.util.Durations; import io.grpc.stub.StreamObserver; import java.time.Duration; From e6272b8e2d9a20f1f3aef592f90359c36c31f79d Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Wed, 6 Jul 2022 11:52:17 +0800 Subject: [PATCH 294/338] [ISSUE #3949] parse client version for grpc clients. --- .../proxy/grpc/v2/client/ClientActivity.java | 18 ++++++++++++++++-- .../grpc/v2/GrpcMessagingApplicationTest.java | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index bd8519279b..38b6d912b3 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -39,6 +39,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.broker.client.ClientChannelInfo; import org.apache.rocketmq.broker.client.ConsumerGroupEvent; import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener; @@ -279,7 +280,7 @@ public class ClientActivity extends AbstractMessingActivity { GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, topicName, clientId); // use topic name as producer group - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, parseClientVersion(ctx.getClientVersion())); this.messagingProcessor.registerProducer(ctx, topicName, clientChannelInfo); this.messagingProcessor.addTransactionSubscription(ctx, topicName, topicName); return channel; @@ -290,7 +291,7 @@ public class ClientActivity extends AbstractMessingActivity { LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); GrpcClientChannel channel = this.grpcChannelManager.createChannel(ctx, consumerGroup, clientId); - ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, MQVersion.Version.V5_0_0.ordinal()); + ClientChannelInfo clientChannelInfo = new ClientChannelInfo(channel, clientId, languageCode, parseClientVersion(ctx.getClientVersion())); this.messagingProcessor.registerConsumer( ctx, @@ -304,6 +305,19 @@ public class ClientActivity extends AbstractMessingActivity { return channel; } + private int parseClientVersion(String clientVersionStr) { + int clientVersion = MQVersion.CURRENT_VERSION; + if (!StringUtils.isEmpty(clientVersionStr)) { + try { + String tmp = StringUtils.upperCase(clientVersionStr); + clientVersion = MQVersion.Version.valueOf(tmp).ordinal(); + } catch (Exception e) { + log.warn("client version from client not recognized: %s", clientVersionStr); + } + } + return clientVersion; + } + protected void reportThreadStackTrace(ProxyContext ctx, Status status, ThreadStackTrace request) { String nonce = request.getNonce(); String threadStack = request.getThreadStackTrace(); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 350f5802a3..27776ba66c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -30,6 +30,7 @@ import io.grpc.Metadata; import io.grpc.stub.StreamObserver; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; @@ -72,6 +73,9 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { @Test public void testQueryRoute() { + int clientVersionCode = MQVersion.Version.valueOf("V3__0_SNAPSHOT").ordinal(); + System.out.println(clientVersionCode); + Metadata metadata = new Metadata(); metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); metadata.put(InterceptorConstants.LANGUAGE, JAVA); From e908d7c8dbc050edf6fbf222d1eeba70c4c2f1df Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Fri, 8 Jul 2022 17:13:16 +0800 Subject: [PATCH 295/338] [ISSUE #3949] parse client version for grpc clients. --- .../rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java index 27776ba66c..350f5802a3 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/GrpcMessagingApplicationTest.java @@ -30,7 +30,6 @@ import io.grpc.Metadata; import io.grpc.stub.StreamObserver; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.config.InitConfigAndLoggerTest; import org.apache.rocketmq.proxy.grpc.interceptor.InterceptorConstants; @@ -73,9 +72,6 @@ public class GrpcMessagingApplicationTest extends InitConfigAndLoggerTest { @Test public void testQueryRoute() { - int clientVersionCode = MQVersion.Version.valueOf("V3__0_SNAPSHOT").ordinal(); - System.out.println(clientVersionCode); - Metadata metadata = new Metadata(); metadata.put(InterceptorConstants.CLIENT_ID, CLIENT_ID); metadata.put(InterceptorConstants.LANGUAGE, JAVA); From cc996007c23e7eff6a6fd7f1f22f12160e6b60ca Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 6 Jul 2022 20:18:16 +0800 Subject: [PATCH 296/338] [ISSUE #3949] add PROPERTY_BORN_HOST into STRING_HASH_SET --- .../java/org/apache/rocketmq/common/message/MessageConst.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java index 25c73bc265..0193fddd7e 100644 --- a/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java +++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java @@ -127,5 +127,6 @@ public class MessageConst { STRING_HASH_SET.add(PROPERTY_CLUSTER); STRING_HASH_SET.add(PROPERTY_MESSAGE_TYPE); STRING_HASH_SET.add(PROPERTY_INNER_MULTI_QUEUE_OFFSET); + STRING_HASH_SET.add(PROPERTY_BORN_HOST); } } From afb89da5818c6acb10e443f15971bbc75b62ceaa Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 6 Jul 2022 20:19:55 +0800 Subject: [PATCH 297/338] [ISSUE #3949] set maxAttempts to retryMaxTimes + 1 --- .../proxy/grpc/v2/common/GrpcClientSettingsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index 1ae6b9e07c..14ddede700 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -98,7 +98,7 @@ public class GrpcClientSettingsManager { resultSettingsBuilder.getSubscriptionBuilder().setFifo(config.isConsumeMessageOrderly()); - resultSettingsBuilder.getBackoffPolicyBuilder().setMaxAttempts(config.getRetryMaxTimes()); + resultSettingsBuilder.getBackoffPolicyBuilder().setMaxAttempts(config.getRetryMaxTimes() + 1); GroupRetryPolicy groupRetryPolicy = config.getGroupRetryPolicy(); if (groupRetryPolicy.getType().equals(GroupRetryPolicyType.EXPONENTIAL)) { From e5124e40aeeb19fcb1dad15cc96d71f10a71ff02 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Wed, 6 Jul 2022 20:58:27 +0800 Subject: [PATCH 298/338] [ISSUE #3949] fix test cases --- .../proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java | 4 ++-- .../java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java index 28a422df0f..96e1e6dd53 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java @@ -70,7 +70,7 @@ public class GrpcClientSettingsManagerTest extends BaseActivityTest { subscriptionGroupConfig.getGroupRetryPolicy().setCustomizedRetryPolicy(new CustomizedRetryPolicy(new long[] {1000})); settings = this.grpcClientSettingsManager.getClientSettings(context); assertEquals(RetryPolicy.newBuilder() - .setMaxAttempts(3) + .setMaxAttempts(4) .setCustomizedBackoff(CustomizedBackoff.newBuilder() .addNext(Durations.fromSeconds(1)) .build()) @@ -81,7 +81,7 @@ public class GrpcClientSettingsManagerTest extends BaseActivityTest { subscriptionGroupConfig.getGroupRetryPolicy().setExponentialRetryPolicy(new ExponentialRetryPolicy(1000, 2000, 3)); settings = this.grpcClientSettingsManager.getClientSettings(context); assertEquals(RetryPolicy.newBuilder() - .setMaxAttempts(10) + .setMaxAttempts(11) .setExponentialBackoff(ExponentialBackoff.newBuilder() .setMax(Durations.fromSeconds(2)) .setInitial(Durations.fromSeconds(1)) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 434aceae96..14f536be5c 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -391,7 +391,7 @@ public class GrpcBaseIT extends BaseConf { int maxDeliveryAttempts = 2; SubscriptionGroupConfig groupConfig = brokerController1.getSubscriptionGroupManager().findSubscriptionGroupConfig(group); - groupConfig.setRetryMaxTimes(maxDeliveryAttempts); + groupConfig.setRetryMaxTimes(maxDeliveryAttempts - 1); brokerController1.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); brokerController2.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); brokerController3.getSubscriptionGroupManager().updateSubscriptionGroupConfig(groupConfig); From 6b45c9963f4f9f0b925b4d2a3bd6d9dfcfd1996c Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 7 Jul 2022 11:47:31 +0800 Subject: [PATCH 299/338] [ISSUE #3949] use SendMessageRequestHeaderV2 --- .../apache/rocketmq/proxy/processor/ProducerProcessor.java | 5 +++-- .../rocketmq/proxy/service/mqclient/MQClientAPIExt.java | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) 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 80ac2f4f6e..0f47393da5 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 @@ -36,6 +36,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; +import org.apache.rocketmq.common.topic.TopicValidator; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; @@ -137,8 +138,8 @@ public class ProducerProcessor extends AbstractProcessor { requestHeader.setProducerGroup(producerGroup); requestHeader.setTopic(message.getTopic()); - requestHeader.setDefaultTopic(""); - requestHeader.setDefaultTopicQueueNums(0); + requestHeader.setDefaultTopic(TopicValidator.AUTO_CREATE_TOPIC_KEY_TOPIC); + requestHeader.setDefaultTopicQueueNums(4); requestHeader.setQueueId(queueId); requestHeader.setSysFlag(sysFlag); requestHeader.setBornTimestamp(System.currentTimeMillis()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java index a174615a96..c3dee4a519 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/mqclient/MQClientAPIExt.java @@ -65,6 +65,7 @@ import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHea import org.apache.rocketmq.common.protocol.header.SearchOffsetRequestHeader; import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; +import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2; import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader; import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData; import org.apache.rocketmq.logging.InternalLogger; @@ -166,7 +167,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { SendMessageRequestHeader requestHeader, long timeoutMillis ) { - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader); + SendMessageRequestHeaderV2 requestHeaderV2 = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV2(requestHeader); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE_V2, requestHeaderV2); request.setBody(msg.getBody()); CompletableFuture future = new CompletableFuture<>(); @@ -196,7 +198,8 @@ public class MQClientAPIExt extends MQClientAPIImpl { SendMessageRequestHeader requestHeader, long timeoutMillis ) { - RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_BATCH_MESSAGE, requestHeader); + SendMessageRequestHeaderV2 requestHeaderV2 = SendMessageRequestHeaderV2.createSendMessageRequestHeaderV2(requestHeader); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_BATCH_MESSAGE, requestHeaderV2); CompletableFuture future = new CompletableFuture<>(); try { From 36caedd10be8978ae5dcf1ba7c0c8a007d382496 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 7 Jul 2022 12:57:53 +0800 Subject: [PATCH 300/338] [ISSUE #3949] change defaultTransactionCheckImmunityTimeInSecond to 30 --- .../main/java/org/apache/rocketmq/proxy/config/ProxyConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 70c02e2c6c..49c7b2b8f6 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 @@ -118,7 +118,7 @@ public class ProxyConfig { private int transactionHeartbeatBatchNum = 100; private long transactionDataExpireScanPeriodMillis = Duration.ofSeconds(10).toMillis(); private long transactionDataMaxWaitClearMillis = Duration.ofSeconds(30).toMillis(); - private long defaultTransactionCheckImmunityTimeInSecond = 60; + private long defaultTransactionCheckImmunityTimeInSecond = 30; private long longPollingReserveTimeInMillis = 100; From 4749dbc0c338d2a7aaf1c8f60385d439df7b0817 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 7 Jul 2022 14:17:34 +0800 Subject: [PATCH 301/338] [ISSUE #3949] Fix LocalMessageService --- .../service/message/LocalMessageService.java | 16 +++++++++++----- .../proxy/service/relay/ProxyChannel.java | 4 ++++ .../apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 1 - 3 files changed, 15 insertions(+), 6 deletions(-) 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 d61ec0342c..ca57457efb 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 @@ -112,12 +112,12 @@ public class LocalMessageService implements MessageService { RemotingCommand response = brokerController.getSendMessageProcessor().processRequest(simpleChannelHandlerContext, request); if (response != null) { invocationContext.handle(response); + channel.eraseInvocationContext(request.getOpaque()); } } catch (Exception e) { future.completeExceptionally(e); - log.error("Failed to process sendMessage command", e); - } finally { channel.eraseInvocationContext(request.getOpaque()); + log.error("Failed to process sendMessage command", e); } return future.thenApply(r -> { SendResult sendResult = new SendResult(); @@ -192,6 +192,7 @@ public class LocalMessageService implements MessageService { @Override public CompletableFuture popMessage(ProxyContext ctx, AddressableMessageQueue messageQueue, PopMessageRequestHeader requestHeader, long timeoutMillis) { + requestHeader.setBornTime(System.currentTimeMillis()); RemotingCommand request = LocalRemotingCommand.createRequestCommand(RequestCode.POP_MESSAGE, requestHeader); CompletableFuture future = new CompletableFuture<>(); SimpleChannel channel = channelManager.createInvocationChannel(ctx); @@ -202,12 +203,12 @@ public class LocalMessageService implements MessageService { RemotingCommand response = brokerController.getPopMessageProcessor().processRequest(simpleChannelHandlerContext, request); if (response != null) { invocationContext.handle(response); + channel.eraseInvocationContext(request.getOpaque()); } } catch (Exception e) { future.completeExceptionally(e); - log.error("Failed to process popMessage command", e); - } finally { channel.eraseInvocationContext(request.getOpaque()); + log.error("Failed to process popMessage command", e); } return future.thenApply(r -> { PopStatus popStatus; @@ -216,7 +217,12 @@ public class LocalMessageService implements MessageService { case ResponseCode.SUCCESS: popStatus = PopStatus.FOUND; ByteBuffer byteBuffer = ByteBuffer.wrap(r.getBody()); - messageExtList = MessageDecoder.decodes(byteBuffer); + messageExtList = MessageDecoder.decodesBatch( + byteBuffer, + true, + false, + true + ); break; case ResponseCode.POLLING_FULL: popStatus = PopStatus.POLLING_FULL; diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java index a9b205a3fb..315f69f5ec 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/relay/ProxyChannel.java @@ -28,6 +28,7 @@ import io.netty.channel.EventLoop; import io.netty.util.concurrent.GlobalEventExecutor; import java.net.SocketAddress; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.concurrent.CompletableFuture; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.message.MessageDecoder; @@ -79,6 +80,9 @@ public abstract class ProxyChannel extends SimpleChannel { .setRemoteAddress(remoteAddress) .setLocalAddress(localAddress); RemotingCommand command = (RemotingCommand) msg; + if (command.getExtFields() == null) { + command.setExtFields(new HashMap<>()); + } switch (command.getCode()) { case RequestCode.CHECK_TRANSACTION_STATE: { CheckTransactionStateRequestHeader header = (CheckTransactionStateRequestHeader) command.readCustomHeader(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 14f536be5c..b80454cffa 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -311,7 +311,6 @@ public class GrpcBaseIT extends BaseConf { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); - int maxDeliveryAttempts = 16; int bodySize = 4 * 1024; // init consumer offset From 4f09b1eea7c986c987e1dac88eafc2707e314580 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 7 Jul 2022 15:21:09 +0800 Subject: [PATCH 302/338] [ISSUE #3949] Add addResourceAndPerm method --- .../acl/plain/PlainAccessResource.java | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java index fdc48534ab..009cbe3949 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java @@ -35,8 +35,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.rocketmq.acl.AccessResource; import org.apache.rocketmq.acl.common.AclException; import org.apache.rocketmq.acl.common.AclUtils; -import org.apache.rocketmq.acl.common.AuthorizationHeader; import org.apache.rocketmq.acl.common.AuthenticationHeader; +import org.apache.rocketmq.acl.common.AuthorizationHeader; import org.apache.rocketmq.acl.common.Permission; import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.common.MixAll; @@ -196,9 +196,7 @@ public class PlainAccessResource implements AccessResource { if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) { HeartbeatRequest request = (HeartbeatRequest) messageV3; if (request.hasGroup()) { - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); + accessResource.addResourceAndPerm(request.getGroup(), Permission.SUB); } } else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { SendMessageRequest request = (SendMessageRequest) messageV3; @@ -211,37 +209,22 @@ public class PlainAccessResource implements AccessResource { throw new AclException("SendMessageRequest, messages' topic is not consistent", ResponseCode.MESSAGE_ILLEGAL); } } - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.PUB); + accessResource.addResourceAndPerm(topic, Permission.PUB); } else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { ReceiveMessageRequest request = (ReceiveMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getMessageQueue().getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); + accessResource.addResourceAndPerm(request.getGroup(), Permission.SUB); + accessResource.addResourceAndPerm(request.getMessageQueue().getTopic(), Permission.SUB); } else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) { AckMessageRequest request = (AckMessageRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); + accessResource.addResourceAndPerm(request.getGroup(), Permission.SUB); + accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB); } else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) { ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3; - Resource group = request.getGroup(); - String groupName = NamespaceUtil.wrapNamespace(group.getResourceNamespace(), group.getName()); - accessResource.addResourceAndPerm(groupName, Permission.SUB); - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.SUB); + accessResource.addResourceAndPerm(request.getGroup(), Permission.SUB); + accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB); } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { EndTransactionRequest request = (EndTransactionRequest) messageV3; - Resource topic = request.getTopic(); - String topicName = NamespaceUtil.wrapNamespace(topic.getResourceNamespace(), topic.getName()); - accessResource.addResourceAndPerm(topicName, Permission.PUB); + accessResource.addResourceAndPerm(request.getTopic(), Permission.PUB); } } catch (Throwable t) { throw new AclException(t.getMessage(), t); @@ -249,6 +232,11 @@ public class PlainAccessResource implements AccessResource { return accessResource; } + private void addResourceAndPerm(Resource resource, byte permission) { + String resourceName = NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName()); + addResourceAndPerm(resourceName, permission); + } + public static PlainAccessResource build(PlainAccessConfig plainAccessConfig, RemoteAddressStrategy remoteAddressStrategy) { PlainAccessResource plainAccessResource = new PlainAccessResource(); plainAccessResource.setAccessKey(plainAccessConfig.getAccessKey()); From 69d58d9ec29057f316a40226d1ef9acc05d1c3b4 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 7 Jul 2022 15:28:45 +0800 Subject: [PATCH 303/338] [ISSUE #3949] Add permission for TelemetryCommand --- .../acl/plain/PlainAccessResource.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java index 009cbe3949..3b43291d52 100644 --- a/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java +++ b/acl/src/main/java/org/apache/rocketmq/acl/plain/PlainAccessResource.java @@ -24,9 +24,13 @@ import apache.rocketmq.v2.Message; import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.SendMessageRequest; +import apache.rocketmq.v2.Subscription; +import apache.rocketmq.v2.SubscriptionEntry; +import apache.rocketmq.v2.TelemetryCommand; import com.google.protobuf.GeneratedMessageV3; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; @@ -225,6 +229,23 @@ public class PlainAccessResource implements AccessResource { } else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) { EndTransactionRequest request = (EndTransactionRequest) messageV3; accessResource.addResourceAndPerm(request.getTopic(), Permission.PUB); + } else if (TelemetryCommand.getDescriptor().getFullName().equals(rpcFullName)) { + TelemetryCommand command = (TelemetryCommand) messageV3; + if (command.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) { + if (command.getSettings().hasPublishing()) { + List topicList = command.getSettings().getPublishing().getTopicsList(); + for (Resource topic : topicList) { + accessResource.addResourceAndPerm(topic, Permission.PUB); + } + } + if (command.getSettings().hasSubscription()) { + Subscription subscription = command.getSettings().getSubscription(); + accessResource.addResourceAndPerm(subscription.getGroup(), Permission.SUB); + for (SubscriptionEntry entry : subscription.getSubscriptionsList()) { + accessResource.addResourceAndPerm(entry.getTopic(), Permission.SUB); + } + } + } } } catch (Throwable t) { throw new AclException(t.getMessage(), t); From 5fb094a2c47f391a387df6eadafb6023f01b3895 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Thu, 7 Jul 2022 15:59:30 +0800 Subject: [PATCH 304/338] [ISSUE #3949] config transactionDataExpireMillis and transactionDataMaxNum --- .../rocketmq/proxy/config/ProxyConfig.java | 19 ++++++++++++++----- .../grpc/v2/producer/SendMessageActivity.java | 12 +++--------- .../AbstractTransactionService.java | 18 ++---------------- .../service/transaction/TransactionData.java | 14 +++++++------- .../transaction/TransactionDataManager.java | 3 +++ 5 files changed, 29 insertions(+), 37 deletions(-) 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 49c7b2b8f6..183e41bd32 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 @@ -118,7 +118,8 @@ public class ProxyConfig { private int transactionHeartbeatBatchNum = 100; private long transactionDataExpireScanPeriodMillis = Duration.ofSeconds(10).toMillis(); private long transactionDataMaxWaitClearMillis = Duration.ofSeconds(30).toMillis(); - private long defaultTransactionCheckImmunityTimeInSecond = 30; + private long transactionDataExpireMillis = Duration.ofSeconds(30).toMillis(); + private int transactionDataMaxNum = 15; private long longPollingReserveTimeInMillis = 100; @@ -601,12 +602,20 @@ public class ProxyConfig { this.transactionDataMaxWaitClearMillis = transactionDataMaxWaitClearMillis; } - public long getDefaultTransactionCheckImmunityTimeInSecond() { - return defaultTransactionCheckImmunityTimeInSecond; + public long getTransactionDataExpireMillis() { + return transactionDataExpireMillis; } - public void setDefaultTransactionCheckImmunityTimeInSecond(long defaultTransactionCheckImmunityTimeInSecond) { - this.defaultTransactionCheckImmunityTimeInSecond = defaultTransactionCheckImmunityTimeInSecond; + public void setTransactionDataExpireMillis(long transactionDataExpireMillis) { + this.transactionDataExpireMillis = transactionDataExpireMillis; + } + + public int getTransactionDataMaxNum() { + return transactionDataMaxNum; + } + + public void setTransactionDataMaxNum(int transactionDataMaxNum) { + this.transactionDataMaxNum = transactionDataMaxNum; } public long getLongPollingReserveTimeInMillis() { 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 11e5c0bfa8..fd68871b4d 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 @@ -26,7 +26,6 @@ import apache.rocketmq.v2.SendResultEntry; import com.google.common.collect.Maps; import com.google.common.hash.Hashing; import com.google.protobuf.ByteString; -import com.google.protobuf.Duration; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; @@ -226,15 +225,10 @@ public class SendMessageActivity extends AbstractMessingActivity { if (messageType.equals(MessageType.TRANSACTION)) { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); - Duration transactionResolveDelay; - if (!message.getSystemProperties().hasOrphanedTransactionRecoveryDuration()) { - transactionResolveDelay = Durations.fromSeconds(ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInSecond()); - } else { - transactionResolveDelay = message.getSystemProperties().getOrphanedTransactionRecoveryDuration(); + if (message.getSystemProperties().hasOrphanedTransactionRecoveryDuration()) { + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, + String.valueOf(Durations.toSeconds(message.getSystemProperties().getOrphanedTransactionRecoveryDuration()))); } - - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, - String.valueOf(Durations.toSeconds(transactionResolveDelay))); } // set delay level or deliver timestamp diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java index 6390bf97ad..262e430c30 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/AbstractTransactionService.java @@ -17,10 +17,8 @@ package org.apache.rocketmq.proxy.service.transaction; -import java.time.Duration; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.StartAndShutdown; @@ -42,11 +40,11 @@ public abstract class AbstractTransactionService implements TransactionService, if (StringUtils.isBlank(brokerName)) { return null; } - long checkImmunityTime = parseCheckImmunityTime(message); TransactionData transactionData = new TransactionData( brokerName, tranStateTableOffset, commitLogOffset, transactionId, - System.currentTimeMillis(), checkImmunityTime); + System.currentTimeMillis(), + ConfigurationManager.getProxyConfig().getTransactionDataExpireMillis()); this.transactionDataManager.addTransactionData( producerGroup, @@ -79,18 +77,6 @@ public abstract class AbstractTransactionService implements TransactionService, this.transactionDataManager.removeTransactionData(producerGroup, transactionData.getTransactionId(), transactionData); } - protected long parseCheckImmunityTime(Message message) { - long checkImmunityTime = ConfigurationManager.getProxyConfig().getDefaultTransactionCheckImmunityTimeInSecond(); - String checkImmunityTimeStr = message.getProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS); - if (StringUtils.isNotBlank(checkImmunityTimeStr)) { - try { - checkImmunityTime = Long.parseLong(checkImmunityTimeStr); - } catch (Exception ignored) { - } - } - return Duration.ofSeconds(checkImmunityTime).toMillis(); - } - protected abstract String getBrokerNameByAddr(String brokerAddr); @Override diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java index 98770a218c..88fbf44396 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionData.java @@ -27,16 +27,16 @@ public class TransactionData implements Comparable { private final long commitLogOffset; private final String transactionId; private final long checkTimestamp; - private final long checkImmunityTime; + private final long expireMs; public TransactionData(String brokerName, long tranStateTableOffset, long commitLogOffset, String transactionId, - long checkTimestamp, long checkImmunityTime) { + long checkTimestamp, long expireMs) { this.brokerName = brokerName; this.tranStateTableOffset = tranStateTableOffset; this.commitLogOffset = commitLogOffset; this.transactionId = transactionId; this.checkTimestamp = checkTimestamp; - this.checkImmunityTime = checkImmunityTime; + this.expireMs = expireMs; } public String getBrokerName() { @@ -59,12 +59,12 @@ public class TransactionData implements Comparable { return checkTimestamp; } - public long getCheckImmunityTime() { - return checkImmunityTime; + public long getExpireMs() { + return expireMs; } public long getExpireTime() { - return checkTimestamp + checkImmunityTime; + return checkTimestamp + expireMs; } @Override @@ -105,7 +105,7 @@ public class TransactionData implements Comparable { .add("commitLogOffset", commitLogOffset) .add("transactionId", transactionId) .add("checkTimestamp", checkTimestamp) - .add("checkImmunityTime", checkImmunityTime) + .add("expireMs", expireMs) .toString(); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java index 594ca5bc11..740afab3ae 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/transaction/TransactionDataManager.java @@ -51,6 +51,9 @@ public class TransactionDataManager implements StartAndShutdown { dataSet = new ConcurrentSkipListSet<>(); } dataSet.add(transactionData); + if (dataSet.size() > ConfigurationManager.getProxyConfig().getTransactionDataMaxNum()) { + dataSet.pollFirst(); + } return dataSet; }); } From c6918ea20f7d93dc4170f3fae6830db3130fdfb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E6=A5=9A?= Date: Thu, 7 Jul 2022 18:57:36 +0800 Subject: [PATCH 305/338] Add GrpcClientSettingsManager#mergeMetric --- .../proxy/grpc/v2/client/ClientActivity.java | 32 ---------------- .../v2/common/GrpcClientSettingsManager.java | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 38b6d912b3..1ada862c8c 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -16,15 +16,11 @@ */ package org.apache.rocketmq.proxy.grpc.v2.client; -import apache.rocketmq.v2.Address; -import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.ClientType; import apache.rocketmq.v2.Code; -import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.FilterExpression; import apache.rocketmq.v2.HeartbeatRequest; import apache.rocketmq.v2.HeartbeatResponse; -import apache.rocketmq.v2.Metric; import apache.rocketmq.v2.NotifyClientTerminationRequest; import apache.rocketmq.v2.NotifyClientTerminationResponse; import apache.rocketmq.v2.Resource; @@ -59,9 +55,6 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.config.ConfigurationManager; -import org.apache.rocketmq.proxy.config.MetricCollectorMode; -import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.grpc.v2.AbstractMessingActivity; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcChannelManager; import org.apache.rocketmq.proxy.grpc.v2.channel.GrpcClientChannel; @@ -226,31 +219,6 @@ public class ClientActivity extends AbstractMessingActivity { StreamObserver responseObserver) { String clientId = ctx.getClientID(); Settings settings = request.getSettings(); - // Construct metric according to the proxy config - final ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); - final MetricCollectorMode metricCollectorMode = - MetricCollectorMode.getEnumByOrdinal(proxyConfig.getMetricCollectorMode()); - final String metricCollectorAddress = proxyConfig.getMetricCollectorAddress(); - final Metric.Builder metricBuilder = Metric.newBuilder(); - switch (metricCollectorMode) { - case ON: - final String[] split = metricCollectorAddress.split(":"); - final String host = split[0]; - final int port = Integer.parseInt(split[1]); - Address address = Address.newBuilder().setHost(host).setPort(port).build(); - final Endpoints endpoints = Endpoints.newBuilder().setScheme(AddressScheme.IPv4) - .addAddresses(address).build(); - metricBuilder.setOn(true).setEndpoints(endpoints); - break; - case PROXY: - metricBuilder.setOn(true).setEndpoints(settings.getAccessPoint()); - case OFF: - default: - metricBuilder.setOn(false); - break; - } - Metric metric = metricBuilder.build(); - settings = settings.toBuilder().setMetric(metric).build(); if (settings.hasPublishing()) { for (Resource topic : settings.getPublishing().getTopicsList()) { validateTopic(topic); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index 14ddede700..53743af558 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -17,8 +17,12 @@ package org.apache.rocketmq.proxy.grpc.v2.common; +import apache.rocketmq.v2.Address; +import apache.rocketmq.v2.AddressScheme; import apache.rocketmq.v2.CustomizedBackoff; +import apache.rocketmq.v2.Endpoints; import apache.rocketmq.v2.ExponentialBackoff; +import apache.rocketmq.v2.Metric; import apache.rocketmq.v2.Publishing; import apache.rocketmq.v2.RetryPolicy; import apache.rocketmq.v2.Settings; @@ -37,6 +41,9 @@ import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.ProxyContext; import org.apache.rocketmq.proxy.common.utils.ProxyUtils; +import org.apache.rocketmq.proxy.config.ConfigurationManager; +import org.apache.rocketmq.proxy.config.MetricCollectorMode; +import org.apache.rocketmq.proxy.config.ProxyConfig; import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class GrpcClientSettingsManager { @@ -81,7 +88,7 @@ public class GrpcClientSettingsManager { settings = mergeSubscriptionData(ctx, settings, GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup())); } - return settings; + return mergeMetric(settings); } private Settings mergeSubscriptionData(ProxyContext ctx, Settings settings, String consumerGroup) { @@ -93,6 +100,35 @@ public class GrpcClientSettingsManager { return mergeSubscriptionData(settings, config); } + private Settings mergeMetric(Settings settings) { + // Construct metric according to the proxy config + final ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); + final MetricCollectorMode metricCollectorMode = + MetricCollectorMode.getEnumByOrdinal(proxyConfig.getMetricCollectorMode()); + final String metricCollectorAddress = proxyConfig.getMetricCollectorAddress(); + final Metric.Builder metricBuilder = Metric.newBuilder(); + switch (metricCollectorMode) { + case ON: + final String[] split = metricCollectorAddress.split(":"); + final String host = split[0]; + final int port = Integer.parseInt(split[1]); + Address address = Address.newBuilder().setHost(host).setPort(port).build(); + final Endpoints endpoints = Endpoints.newBuilder().setScheme(AddressScheme.IPv4) + .addAddresses(address).build(); + metricBuilder.setOn(true).setEndpoints(endpoints); + break; + case PROXY: + metricBuilder.setOn(true).setEndpoints(settings.getAccessPoint()); + break; + case OFF: + default: + metricBuilder.setOn(false); + break; + } + Metric metric = metricBuilder.build(); + return settings.toBuilder().setMetric(metric).build(); + } + protected static Settings mergeSubscriptionData(Settings settings, SubscriptionGroupConfig config) { Settings.Builder resultSettingsBuilder = settings.toBuilder(); From be02f46b57e729200efbb2e27dacd56c1ea57952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E6=A5=9A?= Date: Mon, 11 Jul 2022 17:09:31 +0800 Subject: [PATCH 306/338] Adapt with the latest protocol --- .../rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index 53743af558..a75fcda5b6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -59,7 +59,6 @@ public class GrpcClientSettingsManager { .build()) .build()) .setPublishing(Publishing.newBuilder() - .setCompressBodyThreshold(4 * 1024) .setMaxBodySize(4 * 1024 * 1024) .build()) .build(); From b6a70e2984878db781fb6c7725dc02104cc0ab7f Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 11 Jul 2022 19:06:47 +0800 Subject: [PATCH 307/338] [ISSUE #3949] add parameter validator --- .../rocketmq/proxy/config/ProxyConfig.java | 89 +++++++++++- .../grpc/v2/AbstractMessingActivity.java | 73 ++-------- .../v2/common/GrpcClientSettingsManager.java | 54 ++++---- .../proxy/grpc/v2/common/GrpcValidator.java | 131 ++++++++++++++++++ .../ChangeInvisibleDurationActivity.java | 3 +- .../v2/consumer/ReceiveMessageActivity.java | 3 + .../grpc/v2/producer/SendMessageActivity.java | 15 +- .../grpc/v2/AbstractMessingActivityTest.java | 4 +- .../common/GrpcClientSettingsManagerTest.java | 2 +- .../ChangeInvisibleDurationActivityTest.java | 40 ++++++ .../consumer/ReceiveMessageActivityTest.java | 48 +++++++ .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 + 12 files changed, 370 insertions(+), 94 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java 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 183e41bd32..12d310a039 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 @@ -60,11 +60,11 @@ public class ProxyConfig { /** * the regex to check topic name, empty string means not to check */ - private String topicNameCheckRegex = "^[%a-zA-Z0-9_-]{1,127}$"; + private String topicNameCheckRegex = "^[%|a-zA-Z0-9_-]{1,127}$"; /** * the regex to check consumer group name, empty string means not to check */ - private String consumerGroupNameCheckRegex = "^[%a-zA-Z0-9_-]{1,255}$"; + private String consumerGroupNameCheckRegex = "^[%a-zA-Z0-9_-]{1,64}$"; /** * max message body size, 0 or negative number means no limit for proxy */ @@ -77,6 +77,17 @@ public class ProxyConfig { * max message group size, 0 or negative number means no limit for proxy */ private int maxMessageGroupSize = 1024; + private long minInvisibleTimeMillsForRecv = Duration.ofSeconds(10).toMillis(); + private long maxInvisibleTimeMills = Duration.ofHours(12).toMillis(); + private long maxDelayTimeMills = Duration.ofDays(1).toMillis(); + private boolean enableTopicMessageTypeCheck = true; + + private int grpcClientProducerMaxAttempts = 3; + private long grpcClientProducerBackoffInitialMillis = 10; + private long grpcClientProducerBackoffMaxMillis = 1000; + private int grpcClientProducerBackoffMultiplier = 2; + private long grpcClientConsumerLongPollingTimeoutMillis = Duration.ofSeconds(30).toMillis(); + private int grpcClientConsumerLongPollingBatchSize = 32; private int channelExpiredInSeconds = 60; private int contextExpiredInSeconds = 30; @@ -132,8 +143,6 @@ public class ProxyConfig { private boolean enableACL = false; - private boolean enableTopicMessageTypeCheck = true; - private int metricCollectorMode = MetricCollectorMode.OFF.getOrdinal(); // Example address: 127.0.0.1:1234 private String metricCollectorAddress = ""; @@ -330,6 +339,78 @@ public class ProxyConfig { this.maxMessageGroupSize = maxMessageGroupSize; } + public long getMinInvisibleTimeMillsForRecv() { + return minInvisibleTimeMillsForRecv; + } + + public void setMinInvisibleTimeMillsForRecv(long minInvisibleTimeMillsForRecv) { + this.minInvisibleTimeMillsForRecv = minInvisibleTimeMillsForRecv; + } + + public long getMaxInvisibleTimeMills() { + return maxInvisibleTimeMills; + } + + public void setMaxInvisibleTimeMills(long maxInvisibleTimeMills) { + this.maxInvisibleTimeMills = maxInvisibleTimeMills; + } + + public long getMaxDelayTimeMills() { + return maxDelayTimeMills; + } + + public void setMaxDelayTimeMills(long maxDelayTimeMills) { + this.maxDelayTimeMills = maxDelayTimeMills; + } + + public int getGrpcClientProducerMaxAttempts() { + return grpcClientProducerMaxAttempts; + } + + public void setGrpcClientProducerMaxAttempts(int grpcClientProducerMaxAttempts) { + this.grpcClientProducerMaxAttempts = grpcClientProducerMaxAttempts; + } + + public long getGrpcClientProducerBackoffInitialMillis() { + return grpcClientProducerBackoffInitialMillis; + } + + public void setGrpcClientProducerBackoffInitialMillis(long grpcClientProducerBackoffInitialMillis) { + this.grpcClientProducerBackoffInitialMillis = grpcClientProducerBackoffInitialMillis; + } + + public long getGrpcClientProducerBackoffMaxMillis() { + return grpcClientProducerBackoffMaxMillis; + } + + public void setGrpcClientProducerBackoffMaxMillis(long grpcClientProducerBackoffMaxMillis) { + this.grpcClientProducerBackoffMaxMillis = grpcClientProducerBackoffMaxMillis; + } + + public int getGrpcClientProducerBackoffMultiplier() { + return grpcClientProducerBackoffMultiplier; + } + + public void setGrpcClientProducerBackoffMultiplier(int grpcClientProducerBackoffMultiplier) { + this.grpcClientProducerBackoffMultiplier = grpcClientProducerBackoffMultiplier; + } + + public long getGrpcClientConsumerLongPollingTimeoutMillis() { + return grpcClientConsumerLongPollingTimeoutMillis; + } + + public void setGrpcClientConsumerLongPollingTimeoutMillis(long grpcClientConsumerLongPollingTimeoutMillis) { + this.grpcClientConsumerLongPollingTimeoutMillis = grpcClientConsumerLongPollingTimeoutMillis; + } + + public int getGrpcClientConsumerLongPollingBatchSize() { + return grpcClientConsumerLongPollingBatchSize; + } + + public void setGrpcClientConsumerLongPollingBatchSize(int grpcClientConsumerLongPollingBatchSize) { + this.grpcClientConsumerLongPollingBatchSize = grpcClientConsumerLongPollingBatchSize; + } + public int getChannelExpiredInSeconds() { return channelExpiredInSeconds; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java index 8b948bfc4e..13b855768a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivity.java @@ -16,22 +16,13 @@ */ package org.apache.rocketmq.proxy.grpc.v2; -import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Resource; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; -import org.apache.commons.lang3.StringUtils; -import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.LoggerName; -import org.apache.rocketmq.common.topic.TopicValidator; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; -import org.apache.rocketmq.proxy.config.ConfigurationManager; 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.GrpcProxyException; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcValidator; import org.apache.rocketmq.proxy.processor.MessagingProcessor; public abstract class AbstractMessingActivity { @@ -40,8 +31,6 @@ public abstract class AbstractMessingActivity { protected final GrpcClientSettingsManager grpcClientSettingsManager; protected final GrpcChannelManager grpcChannelManager; - protected static final Map CHECK_PATTERN_CACHE = new ConcurrentHashMap<>(); - public AbstractMessingActivity(MessagingProcessor messagingProcessor, GrpcClientSettingsManager grpcClientSettingsManager, GrpcChannelManager grpcChannelManager) { this.messagingProcessor = messagingProcessor; @@ -49,61 +38,23 @@ public abstract class AbstractMessingActivity { this.grpcChannelManager = grpcChannelManager; } - protected Pattern getPattern(String regex) { - return CHECK_PATTERN_CACHE.compute(regex, (regexKey, oldPattern) -> { - try { - return Pattern.compile(regex); - } catch (Exception e) { - log.error("create check pattern failed. regex:{}", regex, e); - return oldPattern; - } - }); - } - protected void validateTopic(Resource topic) { - String topicName = GrpcConverter.getInstance().wrapResourceWithNamespace(topic); - if (StringUtils.isBlank(topicName)) { - throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "topic name cannot be empty"); - } - if (TopicValidator.isSystemTopic(topicName)) { - throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "cannot access system topic"); - } - String regex = ConfigurationManager.getProxyConfig().getTopicNameCheckRegex(); - if (StringUtils.isBlank(regex)) { - return; - } - Pattern pattern = getPattern(regex); - if (pattern == null) { - throw new GrpcProxyException(Code.INTERNAL_SERVER_ERROR, "get topic name check pattern failed"); - } - if (!pattern.matcher(topicName).matches()) { - throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "the format of topic is not correct"); - } + GrpcValidator.getInstance().validateTopic(topic); } protected void validateConsumerGroup(Resource consumerGroup) { - String consumerGroupName = GrpcConverter.getInstance().wrapResourceWithNamespace(consumerGroup); - if (StringUtils.isBlank(consumerGroupName)) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "consumer group cannot be empty"); - } - if (MixAll.isSysConsumerGroup(consumerGroupName)) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "cannot use system consumer group"); - } - String regex = ConfigurationManager.getProxyConfig().getConsumerGroupNameCheckRegex(); - if (StringUtils.isBlank(regex)) { - return; - } - Pattern pattern = getPattern(regex); - if (pattern == null) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "get consumer group check pattern failed"); - } - if (!pattern.matcher(consumerGroupName).matches()) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "the format of consumer group is not correct"); - } + GrpcValidator.getInstance().validateConsumerGroup(consumerGroup); } protected void validateTopicAndConsumerGroup(Resource topic, Resource consumerGroup) { - validateTopic(topic); - validateConsumerGroup(consumerGroup); + GrpcValidator.getInstance().validateTopicAndConsumerGroup(topic, consumerGroup); + } + + protected void validateInvisibleTime(long invisibleTime) { + GrpcValidator.getInstance().validateInvisibleTime(invisibleTime); + } + + protected void validateInvisibleTime(long invisibleTime, long minInvisibleTime) { + GrpcValidator.getInstance().validateInvisibleTime(invisibleTime, minInvisibleTime); } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index a75fcda5b6..e1bf63bcd2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -40,7 +40,6 @@ import org.apache.rocketmq.common.subscription.GroupRetryPolicy; import org.apache.rocketmq.common.subscription.GroupRetryPolicyType; import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.proxy.common.ProxyContext; -import org.apache.rocketmq.proxy.common.utils.ProxyUtils; import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.config.MetricCollectorMode; import org.apache.rocketmq.proxy.config.ProxyConfig; @@ -48,27 +47,6 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor; public class GrpcClientSettingsManager { - // TODO: read config from topic or subscription configManager - protected static final Settings DEFAULT_PRODUCER_SETTINGS = Settings.newBuilder() - .setBackoffPolicy(RetryPolicy.newBuilder() - .setMaxAttempts(3) - .setExponentialBackoff(ExponentialBackoff.newBuilder() - .setInitial(Durations.fromSeconds(1)) - .setMax(Durations.fromSeconds(3)) - .setMultiplier(2) - .build()) - .build()) - .setPublishing(Publishing.newBuilder() - .setMaxBodySize(4 * 1024 * 1024) - .build()) - .build(); - protected static final Settings DEFAULT_CONSUMER_SETTINGS = mergeSubscriptionData(Settings.newBuilder() - .setSubscription(Subscription.newBuilder() - .setReceiveBatchSize(ProxyUtils.MAX_MSG_NUMS_FOR_POP_REQUEST) - .setLongPollingTimeout(Durations.fromSeconds(30)) - .build()) - .build(), new SubscriptionGroupConfig()); - protected static final Map CLIENT_SETTINGS_MAP = new ConcurrentHashMap<>(); private final MessagingProcessor messagingProcessor; @@ -171,13 +149,41 @@ public class GrpcClientSettingsManager { public void updateClientSettings(String clientId, Settings settings) { if (settings.hasPublishing()) { - settings = DEFAULT_PRODUCER_SETTINGS.toBuilder().mergeFrom(settings).build(); + settings = createDefaultProducerSettingsBuilder().mergeFrom(settings).build(); } else if (settings.hasSubscription()) { - settings = DEFAULT_CONSUMER_SETTINGS.toBuilder().mergeFrom(settings).build(); + settings = createDefaultConsumerSettingsBuilder().mergeFrom(settings).build(); } CLIENT_SETTINGS_MAP.put(clientId, settings); } + protected Settings.Builder createDefaultProducerSettingsBuilder() { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + return Settings.newBuilder() + .setBackoffPolicy(RetryPolicy.newBuilder() + .setMaxAttempts(config.getGrpcClientProducerMaxAttempts()) + .setExponentialBackoff(ExponentialBackoff.newBuilder() + .setInitial(Durations.fromMillis(config.getGrpcClientProducerBackoffInitialMillis())) + .setMax(Durations.fromMillis(config.getGrpcClientProducerBackoffMaxMillis())) + .setMultiplier(config.getGrpcClientProducerBackoffMultiplier()) + .build()) + .build()) + .setPublishing(Publishing.newBuilder() + .setValidateMessageType(config.isEnableTopicMessageTypeCheck()) + .setMaxBodySize(config.getMaxMessageSize()) + .build()); + } + + protected Settings.Builder createDefaultConsumerSettingsBuilder() { + ProxyConfig config = ConfigurationManager.getProxyConfig(); + return mergeSubscriptionData(Settings.newBuilder() + .setSubscription(Subscription.newBuilder() + .setReceiveBatchSize(config.getGrpcClientConsumerLongPollingBatchSize()) + .setLongPollingTimeout(Durations.fromMillis(config.getGrpcClientConsumerLongPollingTimeoutMillis())) + .build()) + .build(), new SubscriptionGroupConfig()) + .toBuilder(); + } + public void removeClientSettings(String clientId) { CLIENT_SETTINGS_MAP.remove(clientId); } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java new file mode 100644 index 0000000000..b4e7bc80a5 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java @@ -0,0 +1,131 @@ +/* + * 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.grpc.v2.common; + +import apache.rocketmq.v2.Code; +import apache.rocketmq.v2.Resource; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.common.MixAll; +import org.apache.rocketmq.common.constant.LoggerName; +import org.apache.rocketmq.common.topic.TopicValidator; +import org.apache.rocketmq.logging.InternalLogger; +import org.apache.rocketmq.logging.InternalLoggerFactory; +import org.apache.rocketmq.proxy.config.ConfigurationManager; + +public class GrpcValidator { + protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); + protected static final Map CHECK_PATTERN_CACHE = new ConcurrentHashMap<>(); + + protected static final Object INSTANCE_CREATE_LOCK = new Object(); + protected static volatile GrpcValidator instance; + + public static GrpcValidator getInstance() { + if (instance == null) { + synchronized (INSTANCE_CREATE_LOCK) { + if (instance == null) { + instance = new GrpcValidator(); + } + } + } + return instance; + } + + protected Pattern getPattern(String regex) { + return CHECK_PATTERN_CACHE.compute(regex, (regexKey, oldPattern) -> { + try { + return Pattern.compile(regex); + } catch (Exception e) { + log.error("create check pattern failed. regex:{}", regex, e); + return oldPattern; + } + }); + } + + public void validateTopic(Resource topic) { + validateTopic(GrpcConverter.getInstance().wrapResourceWithNamespace(topic)); + } + + public void validateTopic(String topicName) { + if (StringUtils.isBlank(topicName)) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "topic name cannot be empty"); + } + if (TopicValidator.isSystemTopic(topicName)) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "cannot access system topic"); + } + String regex = ConfigurationManager.getProxyConfig().getTopicNameCheckRegex(); + if (StringUtils.isBlank(regex)) { + return; + } + Pattern pattern = getPattern(regex); + if (pattern == null) { + throw new GrpcProxyException(Code.INTERNAL_SERVER_ERROR, "get topic name check pattern failed"); + } + if (!pattern.matcher(topicName).matches()) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "the format of topic is not correct"); + } + } + + public void validateConsumerGroup(Resource consumerGroup) { + validateConsumerGroup(GrpcConverter.getInstance().wrapResourceWithNamespace(consumerGroup)); + } + + public void validateConsumerGroup(String consumerGroupName) { + if (StringUtils.isBlank(consumerGroupName)) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "consumer group cannot be empty"); + } + if (MixAll.isSysConsumerGroup(consumerGroupName)) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "cannot use system consumer group"); + } + String regex = ConfigurationManager.getProxyConfig().getConsumerGroupNameCheckRegex(); + if (StringUtils.isBlank(regex)) { + return; + } + Pattern pattern = getPattern(regex); + if (pattern == null) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "get consumer group check pattern failed"); + } + if (!pattern.matcher(consumerGroupName).matches()) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "the format of consumer group is not correct"); + } + } + + public void validateTopicAndConsumerGroup(Resource topic, Resource consumerGroup) { + validateTopic(topic); + validateConsumerGroup(consumerGroup); + } + + public void validateInvisibleTime(long invisibleTime) { + validateInvisibleTime(invisibleTime, 0); + } + + public void validateInvisibleTime(long invisibleTime, long minInvisibleTime) { + if (invisibleTime < minInvisibleTime) { + throw new GrpcProxyException(Code.ILLEGAL_INVISIBLE_TIME, "the invisibleTime is too small. min is " + minInvisibleTime); + } + long maxInvisibleTime = ConfigurationManager.getProxyConfig().getMaxInvisibleTimeMills(); + if (maxInvisibleTime <= 0) { + return; + } + if (invisibleTime > maxInvisibleTime) { + throw new GrpcProxyException(Code.ILLEGAL_INVISIBLE_TIME, "the invisibleTime is too large. max is " + maxInvisibleTime); + } + } +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java index 71a71f2297..ff63127bc6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivity.java @@ -49,7 +49,8 @@ public class ChangeInvisibleDurationActivity extends AbstractMessingActivity { try { validateTopicAndConsumerGroup(request.getTopic(), request.getGroup()); - + validateInvisibleTime(Durations.toMillis(request.getInvisibleDuration())); + ReceiptHandle receiptHandle = ReceiptHandle.decode(request.getReceiptHandle()); String group = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index 20326791a7..a5d000d3d2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -84,6 +84,9 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); if (proxyConfig.isEnableProxyAutoRenew() && request.getAutoRenew()) { actualInvisibleTime = proxyConfig.getRenewSliceTimeMillis(); + } else { + validateInvisibleTime(actualInvisibleTime, + ConfigurationManager.getProxyConfig().getMinInvisibleTimeMillsForRecv()); } FilterExpression filterExpression = request.getFilterExpression(); 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 fd68871b4d..589705ca5c 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 @@ -188,6 +188,16 @@ public class SendMessageActivity extends AbstractMessingActivity { } } + protected void validateDelayTime(long deliveryTimestampMs) { + long maxDelay = ConfigurationManager.getProxyConfig().getMaxDelayTimeMills(); + if (maxDelay <= 0) { + return; + } + if (deliveryTimestampMs - System.currentTimeMillis() > maxDelay) { + throw new GrpcProxyException(Code.ILLEGAL_DELIVERY_TIME, "the max delay time of message is too large"); + } + } + protected Map buildMessageProperty(ProxyContext context, apache.rocketmq.v2.Message message, String producerGroup) { org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties @@ -234,7 +244,10 @@ public class SendMessageActivity extends AbstractMessingActivity { // set delay level or deliver timestamp if (message.getSystemProperties().hasDeliveryTimestamp()) { Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); - String timestampString = String.valueOf(Timestamps.toMillis(deliveryTimestamp)); + long deliveryTimestampMs = Timestamps.toMillis(deliveryTimestamp); + validateDelayTime(deliveryTimestampMs); + + String timestampString = String.valueOf(deliveryTimestampMs); MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java index 3dad901daf..ea1b67d01c 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java @@ -63,8 +63,8 @@ public class AbstractMessingActivityTest extends InitConfigAndLoggerTest { assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().build())); assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(MixAll.CID_SYS_RMQ_TRANS).build())); assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName("@").build())); - assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(256)).build())); - messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(255)).build()); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(65)).build())); + messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(64)).build()); } private static String createString(int len) { diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java index 96e1e6dd53..05ed615119 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManagerTest.java @@ -63,7 +63,7 @@ public class GrpcClientSettingsManagerTest extends BaseActivityTest { ProxyContext context = ProxyContext.create().withVal(ContextVariable.CLIENT_ID, CLIENT_ID); Settings settings = this.grpcClientSettingsManager.getClientSettings(context); - assertEquals(settings.getBackoffPolicy(), GrpcClientSettingsManager.DEFAULT_CONSUMER_SETTINGS.getBackoffPolicy()); + assertEquals(settings.getBackoffPolicy(), this.grpcClientSettingsManager.createDefaultConsumerSettingsBuilder().build().getBackoffPolicy()); subscriptionGroupConfig.setRetryMaxTimes(3); subscriptionGroupConfig.getGroupRetryPolicy().setType(GroupRetryPolicyType.CUSTOMIZED); diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java index 79a8648408..44f879f839 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ChangeInvisibleDurationActivityTest.java @@ -23,10 +23,12 @@ import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Resource; import com.google.protobuf.util.Durations; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.consumer.AckResult; import org.apache.rocketmq.client.consumer.AckStatus; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -99,4 +101,42 @@ public class ChangeInvisibleDurationActivityTest extends BaseActivityTest { assertEquals(Code.INTERNAL_SERVER_ERROR, response.getStatus().getCode()); assertEquals(TimeUnit.SECONDS.toMillis(3), invisibleTimeArgumentCaptor.getValue().longValue()); } + + @Test + public void testChangeInvisibleDurationInvisibleTimeTooSmall() throws Throwable { + try { + this.changeInvisibleDurationActivity.changeInvisibleDuration( + createContext(), + ChangeInvisibleDurationRequest.newBuilder() + .setInvisibleDuration(Durations.fromSeconds(-1)) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageId("msgId") + .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000)) + .build() + ).get(); + } catch (ExecutionException executionException) { + GrpcProxyException exception = (GrpcProxyException) executionException.getCause(); + assertEquals(Code.ILLEGAL_INVISIBLE_TIME, exception.getCode()); + } + } + + @Test + public void testChangeInvisibleDurationInvisibleTimeTooLarge() throws Throwable { + try { + this.changeInvisibleDurationActivity.changeInvisibleDuration( + createContext(), + ChangeInvisibleDurationRequest.newBuilder() + .setInvisibleDuration(Durations.fromDays(7)) + .setTopic(Resource.newBuilder().setName(TOPIC).build()) + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageId("msgId") + .setReceiptHandle(buildReceiptHandle(TOPIC, System.currentTimeMillis(), 3000)) + .build() + ).get(); + } catch (ExecutionException executionException) { + GrpcProxyException exception = (GrpcProxyException) executionException.getCause(); + assertEquals(Code.ILLEGAL_INVISIBLE_TIME, exception.getCode()); + } + } } \ 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 105ebe5559..2df5480a73 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 @@ -25,6 +25,7 @@ import apache.rocketmq.v2.ReceiveMessageRequest; import apache.rocketmq.v2.ReceiveMessageResponse; import apache.rocketmq.v2.Resource; import apache.rocketmq.v2.Settings; +import com.google.protobuf.util.Durations; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import java.util.ArrayList; @@ -86,6 +87,7 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setAutoRenew(true) .setFilterExpression(FilterExpression.newBuilder() .setType(FilterType.SQL) .setExpression("") @@ -97,6 +99,51 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { assertEquals(Code.ILLEGAL_FILTER_EXPRESSION, getResponseCodeFromReceiveMessageResponseList(responseArgumentCaptor.getAllValues())); } + @Test + public void testReceiveMessageIllegalInvisibleTimeTooSmall() { + StreamObserver receiveStreamObserver = mock(ServerCallStreamObserver.class); + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + + when(this.grpcClientSettingsManager.getClientSettings(any())).thenReturn(Settings.newBuilder().getDefaultInstanceForType()); + + this.receiveMessageActivity.receiveMessage( + createContext(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setAutoRenew(false) + .setInvisibleDuration(Durations.fromSeconds(0)) + .build(), + receiveStreamObserver + ); + + assertEquals(Code.ILLEGAL_INVISIBLE_TIME, getResponseCodeFromReceiveMessageResponseList(responseArgumentCaptor.getAllValues())); + } + + @Test + public void testReceiveMessageIllegalInvisibleTimeTooLarge() { + StreamObserver receiveStreamObserver = mock(ServerCallStreamObserver.class); + ArgumentCaptor responseArgumentCaptor = ArgumentCaptor.forClass(ReceiveMessageResponse.class); + doNothing().when(receiveStreamObserver).onNext(responseArgumentCaptor.capture()); + + when(this.grpcClientSettingsManager.getClientSettings(any())).thenReturn(Settings.newBuilder().getDefaultInstanceForType()); + + this.receiveMessageActivity.receiveMessage( + createContext(), + ReceiveMessageRequest.newBuilder() + .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) + .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setAutoRenew(false) + .setInvisibleDuration(Durations.fromDays(7)) + .build(), + receiveStreamObserver + ); + + assertEquals(Code.ILLEGAL_INVISIBLE_TIME, getResponseCodeFromReceiveMessageResponseList(responseArgumentCaptor.getAllValues())); + } + + @Test public void testReceiveMessage() { StreamObserver receiveStreamObserver = mock(ServerCallStreamObserver.class); @@ -125,6 +172,7 @@ public class ReceiveMessageActivityTest extends BaseActivityTest { ReceiveMessageRequest.newBuilder() .setGroup(Resource.newBuilder().setName(CONSUMER_GROUP).build()) .setMessageQueue(MessageQueue.newBuilder().setTopic(Resource.newBuilder().setName(TOPIC).build()).build()) + .setAutoRenew(true) .setFilterExpression(FilterExpression.newBuilder() .setType(FilterType.TAG) .setExpression("*") diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index b80454cffa..2d44dd7624 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -147,6 +147,7 @@ public class GrpcBaseIT extends BaseConf { // Set LongPollingReserveTimeInMillis to 500ms to reserve more time for IT ConfigurationManager.getProxyConfig().setLongPollingReserveTimeInMillis(500); ConfigurationManager.getProxyConfig().setRocketMQClusterName(brokerController1.getBrokerConfig().getBrokerClusterName()); + ConfigurationManager.getProxyConfig().setMinInvisibleTimeMillsForRecv(3); blockingStub = createBlockingStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); stub = createStub(createChannel(ConfigurationManager.getProxyConfig().getGrpcServerPort())); @@ -607,6 +608,7 @@ public class GrpcBaseIT extends BaseConf { .setId(-1) .build()) .setBatchSize(1) + .setAutoRenew(false) .setInvisibleDuration(Duration.newBuilder() .setSeconds(3) .build()) From 6634a6a03a5b75fc43c13fab9e5a5706fd89041b Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 11 Jul 2022 19:11:14 +0800 Subject: [PATCH 308/338] [ISSUE #3949] fix test cases --- .../proxy/grpc/v2/common/GrpcClientSettingsManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java index e1bf63bcd2..548bd5efd2 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcClientSettingsManager.java @@ -194,7 +194,11 @@ public class GrpcClientSettingsManager { if (settings == null) { return null; } - return mergeSubscriptionData(ctx, settings, + settings = mergeSubscriptionData(ctx, settings, GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup())); + if (settings == null) { + return null; + } + return mergeMetric(settings); } } From baa36b4ec9d6b4fc55ba1b21d524d6029b21c5ef Mon Sep 17 00:00:00 2001 From: "yuncun.sl" Date: Tue, 12 Jul 2022 16:31:41 +0800 Subject: [PATCH 309/338] pass compile --- .../rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index 3f8dafaff8..c2c2ea3c24 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -133,8 +133,8 @@ public class GrpcClientChannel extends ProxyChannel { this.getTelemetryCommandStreamObserver().onNext(TelemetryCommand.newBuilder() .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(transactionData.getTransactionId()) - .setOrphanedTransactionalMessage(GrpcConverter.getInstance().buildMessage(messageExt)) - .setMessageQueue(GrpcConverter.getInstance().buildMessageQueue(messageExt, transactionData.getBrokerName())) + .setMessage(GrpcConverter.getInstance().buildMessage(messageExt)) +// .setMessageQueue(GrpcConverter.getInstance().buildMessageQueue(messageExt, transactionData.getBrokerName())) .build()) .build()); responseFuture.complete(null); From 72343c9f0856b5354dec0c8bf33bd014eb2fbc18 Mon Sep 17 00:00:00 2001 From: "yuncun.sl" Date: Tue, 12 Jul 2022 16:49:16 +0800 Subject: [PATCH 310/338] pass compile --- .../java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 2d44dd7624..c461a3e2f9 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -678,8 +678,8 @@ public class GrpcBaseIT extends BaseConf { } public void assertRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand command, String messageId) { - assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) - .isEqualTo(messageId); +// assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) +// .isEqualTo(messageId); assertThat(command.getTransactionId()).isNotBlank(); } From 5d10401ab0a677620f73fca65225106ec00826e2 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 13 Jul 2022 11:09:46 +0800 Subject: [PATCH 311/338] Remove annotation --- .../rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java | 1 - .../test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java index c2c2ea3c24..d0ef56159a 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/channel/GrpcClientChannel.java @@ -134,7 +134,6 @@ public class GrpcClientChannel extends ProxyChannel { .setRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand.newBuilder() .setTransactionId(transactionData.getTransactionId()) .setMessage(GrpcConverter.getInstance().buildMessage(messageExt)) -// .setMessageQueue(GrpcConverter.getInstance().buildMessageQueue(messageExt, transactionData.getBrokerName())) .build()) .build()); responseFuture.complete(null); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index c461a3e2f9..276ab9744b 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -678,8 +678,6 @@ public class GrpcBaseIT extends BaseConf { } public void assertRecoverOrphanedTransactionCommand(RecoverOrphanedTransactionCommand command, String messageId) { -// assertThat(command.getOrphanedTransactionalMessage().getSystemProperties().getMessageId()) -// .isEqualTo(messageId); assertThat(command.getTransactionId()).isNotBlank(); } From fc39bd6dcf2a3dabbe3512e86587a0a3bf14355c Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 13 Jul 2022 19:18:03 +0800 Subject: [PATCH 312/338] [ISSUE #3949] Refine README --- proxy/README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/proxy/README.md b/proxy/README.md index 2a704f7a8a..936bd024b0 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -4,9 +4,9 @@ rocketmq-proxy ## Introduction `RocketMQ Proxy` is a stateless component that makes full use of the newly introduced `pop` consumption mechanism to -achieve stateless consumption behavior. `gRPC` protocol is supported now and all the message types including `normal` -, `fifo`, `transaction` and `delay` are supported via `pop`. `Proxy` will translate incoming traffic into -customized `Remoting` protocol to access `Broker` or `Namesrv`. +achieve stateless consumption behavior. `gRPC` protocol is supported by `Proxy` now and all the message types +including `normal`, `fifo`, `transaction` and `delay` are supported via `pop` consumption mode. `Proxy` will translate +incoming traffic into customized `Remoting` protocol to access `Broker` and `Namesrv`. `Proxy` also handles SSL, authorization/authentication and logging/tracing/metrics and is in charge of connection management and traffic governance. @@ -14,23 +14,24 @@ management and traffic governance. ### Multi-language support. `gRPC` combined with `Protocol Buffer` makes it easy to implement clients with both `java` and other programming -languages. See [rocketmq-clients](https://github.com/apache/rocketmq-clients) for more information. +languages while the server side doesn't need extra work to support different programming languages. +See [rocketmq-clients](https://github.com/apache/rocketmq-clients) for more information. ### Multi-protocol support. -With `Proxy` as a traffic interface, it's convenient to implement multiple protocols upon proxy. `gRPC` protocol is -implemented first and the customized `Remoting` protocol will be implemented later. HTTP/1.1 will also be taken into +With `Proxy` served as a traffic interface, it's convenient to implement multiple protocols upon proxy. `gRPC` protocol +is implemented first and the customized `Remoting` protocol will be implemented later. HTTP/1.1 will also be taken into consideration. ## Architecture -`RocketMQ Proxy` has two deployment modes: `Cluster` mode and `Local` mode. With both modes, `Pop` mode is natively supported -in `Proxy`. +`RocketMQ Proxy` has two deployment modes: `Cluster` mode and `Local` mode. With both modes, `Pop` mode is natively +supported in `Proxy`. ### `Cluster` mode -While in `Cluster` mode, `Proxy` is an independent cluster that communicates with `Broker` with remote procedure call. In -this scenario, `Proxy` acts as a stateless computing component while `Broker` is a stateful component with local +While in `Cluster` mode, `Proxy` is an independent cluster that communicates with `Broker` with remote procedure call. +In this scenario, `Proxy` acts as a stateless computing component while `Broker` is a stateful component with local storage. This form of deployment introduces the architecture of separation of computing and storage for RocketMQ. Due to the separation of computing and storage, `RocketMQ Proxy` can be scaled out indefinitely in `Cluster` mode to From b136f9bb6725867dcc5d00798addd0de7382ffb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Jul 2022 09:08:45 +0800 Subject: [PATCH 313/338] Bump commons-io from 2.6 to 2.7 (#4600) Bumps commons-io from 2.6 to 2.7. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7f14a1d864..f416700e31 100644 --- a/pom.xml +++ b/pom.xml @@ -108,7 +108,7 @@ 3.20.0-GA 4.2.2 3.4 - 2.6 + 2.7 31.0.1-jre 0.3.1-alpha 1.2.17 From 67517545b2075509ff1563e4b04e781193e6b401 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 14 Jul 2022 14:19:41 +0800 Subject: [PATCH 314/338] fix pom.xml --- pom.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index e3ee11dc31..241356f7c4 100644 --- a/pom.xml +++ b/pom.xml @@ -124,11 +124,13 @@ 6.0.53 1.0-beta-4 1.4.2 + 2.0.0-SNAPSHOT 1.45.0 + 3.20.1 4.13.2 - 2.6.0 + 3.22.0 3.10.0 4.1.0 0.30 @@ -483,7 +485,7 @@ ${project.groupId} rocketmq-proto - 2.0.0-SNAPSHOT + ${rocketmq-proto.version} ${project.groupId} @@ -726,7 +728,6 @@ org.awaitility awaitility ${awaitility.version} - test com.google.truth @@ -762,7 +763,7 @@ com.google.protobuf protobuf-java-util - 3.20.1 + ${protobuf-java-util.version} @@ -772,16 +773,19 @@ junit junit ${junit.version} + test org.assertj assertj-core ${assertj-core.version} + test org.mockito mockito-core ${mockito-core.version} + test org.awaitility From 1a542d9450df39f5cb80ebf51ed1642d7707b3ce Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Thu, 14 Jul 2022 14:24:43 +0800 Subject: [PATCH 315/338] add rmq-proxy.json to license ignore --- .licenserc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.licenserc.yaml b/.licenserc.yaml index a6c5cd0bb6..3d6205e930 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -34,12 +34,14 @@ header: - 'src/test/**/*.log' - '*/src/test/resources/META-INF/service/*' - '*/src/main/resources/META-INF/service/*' + - '*/src/test/resources/rmq-proxy-home/conf/rmq-proxy.json' - '**/target/**' - '**/*.iml' - 'docs/**' - 'localbin/**' - 'distribution/LICENSE-BIN' - 'distribution/NOTICE-BIN' + - 'distribution/conf/rmq-proxy.json' comment: on-failure \ No newline at end of file From 74e1a60b37829e3730ad165ff6ea73b6c52b3dfe Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 14 Jul 2022 17:16:05 +0800 Subject: [PATCH 316/338] [ISSUE #4597] Fix inaccurate judgement --- .../rocketmq/tools/command/queue/QueryConsumeQueueCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java index fafe71c63b..32055cdc3a 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java @@ -22,6 +22,7 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; +import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.common.protocol.body.ConsumeQueueData; import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody; import org.apache.rocketmq.common.protocol.route.TopicRouteData; @@ -104,7 +105,7 @@ public class QueryConsumeQueueCommand implements SubCommand { consumerGroup = commandLine.getOptionValue("g").trim(); } - if (broker == null || broker == "") { + if (StringUtils.isEmpty(broker)) { TopicRouteData topicRouteData = defaultMQAdminExt.examineTopicRouteInfo(topic); if (topicRouteData == null || topicRouteData.getBrokerDatas() == null From 225bc42f9597cd9ff38fd01c2d5168c68a7f5cf8 Mon Sep 17 00:00:00 2001 From: rongtong Date: Fri, 15 Jul 2022 10:21:11 +0800 Subject: [PATCH 317/338] Fix the wrong format output of clusterlist command (#4608) --- .../rocketmq/tools/command/cluster/ClusterListSubCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/cluster/ClusterListSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/cluster/ClusterListSubCommand.java index ecd343cc19..7e15ef4f72 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/command/cluster/ClusterListSubCommand.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/command/cluster/ClusterListSubCommand.java @@ -180,7 +180,7 @@ public class ClusterListSubCommand implements SubCommand { private void printClusterBaseInfo(final Set clusterNames, final DefaultMQAdminExt defaultMQAdminExt, final ClusterInfo clusterInfo) { - System.out.printf("%-16s %-22s %-4s %-22s %-16s %19s %19s %10s %5s %6s %-10%n", + System.out.printf("%-16s %-22s %-4s %-22s %-16s %19s %19s %10s %5s %6s %10s%n", "#Cluster Name", "#Broker Name", "#BID", From 00da3e7249d2339717d96f7ea2ab8e4a2fd4242c Mon Sep 17 00:00:00 2001 From: cserwen Date: Fri, 15 Jul 2022 17:33:54 +0800 Subject: [PATCH 318/338] [ISSUE #4606] Build trace msgs for DefaultLitePullConsumer when poll is called Co-authored-by: dengzhiwen1 --- .../consumer/DefaultLitePullConsumerImpl.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java index 58dfd8edaa..9b300a87e6 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java @@ -568,6 +568,18 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner { assignedMessageQueue.updateConsumeOffset(consumeRequest.getMessageQueue(), offset); //If namespace not null , reset Topic without namespace. this.resetTopic(messages); + if (!this.consumeMessageHookList.isEmpty()) { + ConsumeMessageContext consumeMessageContext = new ConsumeMessageContext(); + consumeMessageContext.setNamespace(defaultLitePullConsumer.getNamespace()); + consumeMessageContext.setConsumerGroup(this.groupName()); + consumeMessageContext.setMq(consumeRequest.getMessageQueue()); + consumeMessageContext.setMsgList(messages); + consumeMessageContext.setSuccess(false); + this.executeHookBefore(consumeMessageContext); + consumeMessageContext.setStatus(ConsumeConcurrentlyStatus.CONSUME_SUCCESS.toString()); + consumeMessageContext.setSuccess(true); + this.executeHookAfter(consumeMessageContext); + } return messages; } } catch (InterruptedException ignore) { @@ -949,18 +961,6 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner { null ); this.pullAPIWrapper.processPullResult(mq, pullResult, subscriptionData); - if (!this.consumeMessageHookList.isEmpty()) { - ConsumeMessageContext consumeMessageContext = new ConsumeMessageContext(); - consumeMessageContext.setNamespace(defaultLitePullConsumer.getNamespace()); - consumeMessageContext.setConsumerGroup(this.groupName()); - consumeMessageContext.setMq(mq); - consumeMessageContext.setMsgList(pullResult.getMsgFoundList()); - consumeMessageContext.setSuccess(false); - this.executeHookBefore(consumeMessageContext); - consumeMessageContext.setStatus(ConsumeConcurrentlyStatus.CONSUME_SUCCESS.toString()); - consumeMessageContext.setSuccess(true); - this.executeHookAfter(consumeMessageContext); - } return pullResult; } From 870e8e462e861739a30babef99b77650667ec033 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 16 Jul 2022 20:54:14 +0800 Subject: [PATCH 319/338] Fix issue 4617 --- .../java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java index 09cfecf171..89a6d7c0bf 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/slave/SlaveSynchronize.java @@ -47,8 +47,8 @@ public class SlaveSynchronize { public void setMasterAddr(String masterAddr) { if (!StringUtils.equals(this.masterAddr, masterAddr)) { - this.masterAddr = masterAddr; LOGGER.info("Update master address from {} to {}", this.masterAddr, masterAddr); + this.masterAddr = masterAddr; } } From c1b14b0dde6084f9799d912cf88228e292c89f5d Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 16 Jul 2022 22:23:23 +0800 Subject: [PATCH 320/338] Fix typo --- .../trace/hook/SendMessageTraceHookImpl.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java b/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java index 80c7babdaa..21e2bd9220 100644 --- a/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java +++ b/client/src/main/java/org/apache/rocketmq/client/trace/hook/SendMessageTraceHookImpl.java @@ -46,12 +46,12 @@ public class SendMessageTraceHookImpl implements SendMessageHook { if (context == null || context.getMessage().getTopic().startsWith(((AsyncTraceDispatcher) localDispatcher).getTraceTopicName())) { return; } - //build the context content of TuxeTraceContext - TraceContext tuxeContext = new TraceContext(); - tuxeContext.setTraceBeans(new ArrayList(1)); - context.setMqTraceContext(tuxeContext); - tuxeContext.setTraceType(TraceType.Pub); - tuxeContext.setGroupName(NamespaceUtil.withoutNamespace(context.getProducerGroup())); + //build the context content of TraceContext + TraceContext traceContext = new TraceContext(); + traceContext.setTraceBeans(new ArrayList(1)); + context.setMqTraceContext(traceContext); + traceContext.setTraceType(TraceType.Pub); + traceContext.setGroupName(NamespaceUtil.withoutNamespace(context.getProducerGroup())); //build the data bean object of message trace TraceBean traceBean = new TraceBean(); traceBean.setTopic(NamespaceUtil.withoutNamespace(context.getMessage().getTopic())); @@ -60,7 +60,7 @@ public class SendMessageTraceHookImpl implements SendMessageHook { traceBean.setStoreHost(context.getBrokerAddr()); traceBean.setBodyLength(context.getMessage().getBody().length); traceBean.setMsgType(context.getMsgType()); - tuxeContext.getTraceBeans().add(traceBean); + traceContext.getTraceBeans().add(traceBean); } @Override @@ -80,19 +80,19 @@ public class SendMessageTraceHookImpl implements SendMessageHook { return; } - TraceContext tuxeContext = (TraceContext) context.getMqTraceContext(); - TraceBean traceBean = tuxeContext.getTraceBeans().get(0); - int costTime = (int) ((System.currentTimeMillis() - tuxeContext.getTimeStamp()) / tuxeContext.getTraceBeans().size()); - tuxeContext.setCostTime(costTime); + TraceContext traceContext = (TraceContext) context.getMqTraceContext(); + TraceBean traceBean = traceContext.getTraceBeans().get(0); + int costTime = (int) ((System.currentTimeMillis() - traceContext.getTimeStamp()) / traceContext.getTraceBeans().size()); + traceContext.setCostTime(costTime); if (context.getSendResult().getSendStatus().equals(SendStatus.SEND_OK)) { - tuxeContext.setSuccess(true); + traceContext.setSuccess(true); } else { - tuxeContext.setSuccess(false); + traceContext.setSuccess(false); } - tuxeContext.setRegionId(context.getSendResult().getRegionId()); + traceContext.setRegionId(context.getSendResult().getRegionId()); traceBean.setMsgId(context.getSendResult().getMsgId()); traceBean.setOffsetMsgId(context.getSendResult().getOffsetMsgId()); - traceBean.setStoreTime(tuxeContext.getTimeStamp() + costTime / 2); - localDispatcher.append(tuxeContext); + traceBean.setStoreTime(traceContext.getTimeStamp() + costTime / 2); + localDispatcher.append(traceContext); } } From 3ee603a49b04c0b602ff8eb45b3ef4330293fba8 Mon Sep 17 00:00:00 2001 From: rongtong Date: Mon, 18 Jul 2022 09:19:43 +0800 Subject: [PATCH 321/338] Try to make CI test more stable (#4616) --- .../rocketmq/test/statictopic/StaticTopicIT.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java b/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java index b198c7a7ac..29b92d5f4a 100644 --- a/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/statictopic/StaticTopicIT.java @@ -108,7 +108,7 @@ public class StaticTopicIT extends BaseConf { RMQNormalProducer producer = getProducer(nsAddr, topic); RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListener()); int queueNum = 10; - int msgEachQueue = 100; + int msgEachQueue = 10; { Set brokers = ImmutableSet.of(broker1Name); MQAdminTestUtils.createStaticTopicWithCommand(topic, queueNum, brokers, null, nsAddr); @@ -207,7 +207,7 @@ public class StaticTopicIT extends BaseConf { } private void consumeMessagesAndCheck(RMQNormalProducer producer, RMQNormalConsumer consumer, String topic, int queueNum, int msgEachQueue, int startGen, int genNum) { - consumer.getListener().waitForMessageConsume(producer.getAllMsgBody(), 30000); + consumer.getListener().waitForMessageConsume(producer.getAllMsgBody(), 60000); // System.out.println("produce:" + producer.getAllMsgBody().size()); // System.out.println("consume:" + consumer.getListener().getAllMsgBody().size()); @@ -243,7 +243,7 @@ public class StaticTopicIT extends BaseConf { RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListener()); int queueNum = 10; - int msgEachQueue = 100; + int msgEachQueue = 10; //create static topic Map localBrokerConfigMap = MQAdminTestUtils.createStaticTopic(topic, queueNum, getBrokers(), defaultMQAdminExt); //check the static topic config @@ -275,7 +275,7 @@ public class StaticTopicIT extends BaseConf { RMQNormalConsumer consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListener()); int queueNum = 1; - int msgEachQueue = 100; + int msgEachQueue = 10; //create send consume { Set targetBrokers = ImmutableSet.of(broker1Name); @@ -346,7 +346,7 @@ public class StaticTopicIT extends BaseConf { long start = System.currentTimeMillis(); int queueNum = 10; - int msgEachQueue = 100; + int msgEachQueue = 10; //create static topic { Set targetBrokers = ImmutableSet.of(broker1Name); From ac6ccc5445be2ecacd306f9fc804e2c71741e24b Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Fri, 15 Jul 2022 19:43:00 +0800 Subject: [PATCH 322/338] [ISSUE #3905] Support bname in protocol --- .../store/RemoteBrokerOffsetStore.java | 2 + .../rocketmq/client/impl/MQAdminImpl.java | 10 ++-- .../rocketmq/client/impl/MQClientAPIImpl.java | 48 +++++++++++++++---- .../client/impl/consumer/PullAPIWrapper.java | 2 +- .../client/impl/MQClientAPIImplTest.java | 7 +-- .../tools/admin/DefaultMQAdminExt.java | 1 + .../tools/admin/DefaultMQAdminExtImpl.java | 8 ++-- .../rocketmq/tools/admin/MQAdminExt.java | 1 + .../tools/admin/DefaultMQAdminExtTest.java | 33 +++++++------ 9 files changed, 72 insertions(+), 40 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java index 4afe871afc..2817f7d8fc 100644 --- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java +++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java @@ -213,6 +213,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore { requestHeader.setConsumerGroup(this.groupName); requestHeader.setQueueId(mq.getQueueId()); requestHeader.setCommitOffset(offset); + requestHeader.setBname(mq.getBrokerName()); if (isOneway) { this.mQClientFactory.getMQClientAPIImpl().updateConsumerOffsetOneway( @@ -239,6 +240,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore { requestHeader.setTopic(mq.getTopic()); requestHeader.setConsumerGroup(this.groupName); requestHeader.setQueueId(mq.getQueueId()); + requestHeader.setBname(mq.getBrokerName()); return this.mQClientFactory.getMQClientAPIImpl().queryConsumerOffset( findBrokerResult.getBrokerAddr(), requestHeader, 1000 * 5); 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 8d3a2e9190..3852785946 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 @@ -193,8 +193,7 @@ public class MQAdminImpl { if (brokerAddr != null) { try { - return this.mQClientFactory.getMQClientAPIImpl().searchOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), timestamp, - timeoutMillis); + return this.mQClientFactory.getMQClientAPIImpl().searchOffset(brokerAddr, mq, timestamp, timeoutMillis); } catch (Exception e) { throw new MQClientException("Invoke Broker[" + brokerAddr + "] exception", e); } @@ -212,7 +211,7 @@ public class MQAdminImpl { if (brokerAddr != null) { try { - return this.mQClientFactory.getMQClientAPIImpl().getMaxOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), timeoutMillis); + return this.mQClientFactory.getMQClientAPIImpl().getMaxOffset(brokerAddr, mq, timeoutMillis); } catch (Exception e) { throw new MQClientException("Invoke Broker[" + brokerAddr + "] exception", e); } @@ -230,7 +229,7 @@ public class MQAdminImpl { if (brokerAddr != null) { try { - return this.mQClientFactory.getMQClientAPIImpl().getMinOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), timeoutMillis); + return this.mQClientFactory.getMQClientAPIImpl().getMinOffset(brokerAddr, mq, timeoutMillis); } catch (Exception e) { throw new MQClientException("Invoke Broker[" + brokerAddr + "] exception", e); } @@ -248,8 +247,7 @@ public class MQAdminImpl { if (brokerAddr != null) { try { - return this.mQClientFactory.getMQClientAPIImpl().getEarliestMsgStoretime(brokerAddr, mq.getTopic(), mq.getQueueId(), - timeoutMillis); + return this.mQClientFactory.getMQClientAPIImpl().getEarliestMsgStoretime(brokerAddr, mq, timeoutMillis); } catch (Exception e) { throw new MQClientException("Invoke Broker[" + brokerAddr + "] 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 1d33219536..528f5646e2 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 @@ -1136,6 +1136,7 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { throw new MQBrokerException(response.getCode(), response.getRemark(), addr); } + @Deprecated public long searchOffset(final String addr, final String topic, final int queueId, final long timestamp, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException { @@ -1161,11 +1162,37 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { throw new MQBrokerException(response.getCode(), response.getRemark(), addr); } - public long getMaxOffset(final String addr, final String topic, final int queueId, final long timeoutMillis) + public long searchOffset(final String addr, final MessageQueue messageQueue, final long timestamp, final long timeoutMillis) + throws RemotingException, MQBrokerException, InterruptedException { + SearchOffsetRequestHeader requestHeader = new SearchOffsetRequestHeader(); + requestHeader.setTopic(messageQueue.getTopic()); + requestHeader.setQueueId(messageQueue.getQueueId()); + requestHeader.setBname(messageQueue.getBrokerName()); + requestHeader.setTimestamp(timestamp); + RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, requestHeader); + + RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), + request, timeoutMillis); + assert response != null; + switch (response.getCode()) { + case ResponseCode.SUCCESS: { + SearchOffsetResponseHeader responseHeader = + (SearchOffsetResponseHeader) response.decodeCommandCustomHeader(SearchOffsetResponseHeader.class); + return responseHeader.getOffset(); + } + default: + break; + } + + throw new MQBrokerException(response.getCode(), response.getRemark(), addr); + } + + public long getMaxOffset(final String addr, final MessageQueue messageQueue, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException { GetMaxOffsetRequestHeader requestHeader = new GetMaxOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); + requestHeader.setTopic(messageQueue.getTopic()); + requestHeader.setQueueId(messageQueue.getQueueId()); + requestHeader.setBname(messageQueue.getBrokerName()); RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MAX_OFFSET, requestHeader); RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), @@ -1212,11 +1239,12 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { throw new MQBrokerException(response.getCode(), response.getRemark(), addr); } - public long getMinOffset(final String addr, final String topic, final int queueId, final long timeoutMillis) + public long getMinOffset(final String addr, final MessageQueue messageQueue, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException { GetMinOffsetRequestHeader requestHeader = new GetMinOffsetRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); + requestHeader.setTopic(messageQueue.getTopic()); + requestHeader.setQueueId(messageQueue.getQueueId()); + requestHeader.setBname(messageQueue.getBrokerName()); RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MIN_OFFSET, requestHeader); RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), @@ -1236,12 +1264,12 @@ public class MQClientAPIImpl implements NameServerUpdateCallback { throw new MQBrokerException(response.getCode(), response.getRemark(), addr); } - public long getEarliestMsgStoretime(final String addr, final String topic, final int queueId, - final long timeoutMillis) + public long getEarliestMsgStoretime(final String addr, final MessageQueue mq, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException { GetEarliestMsgStoretimeRequestHeader requestHeader = new GetEarliestMsgStoretimeRequestHeader(); - requestHeader.setTopic(topic); - requestHeader.setQueueId(queueId); + requestHeader.setTopic(mq.getTopic()); + requestHeader.setQueueId(mq.getQueueId()); + requestHeader.setBname(mq.getBrokerName()); RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_EARLIEST_MSG_STORETIME, requestHeader); RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java index 6ce8e261ca..187b2573dc 100644 --- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java +++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java @@ -227,13 +227,13 @@ public class PullAPIWrapper { requestHeader.setSubVersion(subVersion); requestHeader.setMaxMsgBytes(maxSizeInBytes); requestHeader.setExpressionType(expressionType); + requestHeader.setBname(mq.getBrokerName()); String brokerAddr = findBrokerResult.getBrokerAddr(); if (PullSysFlag.hasClassFilterFlag(sysFlagInner)) { brokerAddr = computePullFromWhichFilterServer(mq.getTopic(), brokerAddr); } - PullResult pullResult = this.mQClientFactory.getMQClientAPIImpl().pullMessage( brokerAddr, requestHeader, 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 02445b31fc..1e5f507c2f 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 @@ -41,6 +41,7 @@ import org.apache.rocketmq.common.PlainAccessConfig; import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageConst; +import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.protocol.RequestCode; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; @@ -712,7 +713,7 @@ public class MQClientAPIImplTest { } }).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong()); - long offset = mqClientAPI.getMaxOffset(brokerAddr, topic, 0, 10000); + long offset = mqClientAPI.getMaxOffset(brokerAddr, new MessageQueue(topic, brokerName, 0), 10000); assertThat(offset).isEqualTo(100L); } @@ -733,7 +734,7 @@ public class MQClientAPIImplTest { } }).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong()); - long offset = mqClientAPI.getMinOffset(brokerAddr, topic, 0, 10000); + long offset = mqClientAPI.getMinOffset(brokerAddr, new MessageQueue(topic, brokerName, 0), 10000); assertThat(offset).isEqualTo(100L); } @@ -754,7 +755,7 @@ public class MQClientAPIImplTest { } }).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong()); - long t = mqClientAPI.getEarliestMsgStoretime(brokerAddr, topic, 0, 10000); + long t = mqClientAPI.getEarliestMsgStoretime(brokerAddr, new MessageQueue(topic, brokerName, 0), 10000); assertThat(t).isEqualTo(100L); } diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java index 311beb7f89..328c673db5 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java @@ -734,6 +734,7 @@ public class DefaultMQAdminExt extends ClientConfig implements MQAdminExt { this.defaultMQAdminExtImpl.createStaticTopic(addr, defaultTopic, topicConfig, mappingDetail, force); } + @Deprecated @Override public long searchOffset(final String brokerAddr, final String topicName, final int queueId, final long timestamp, final long timeoutMillis) diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java index eceaf040f8..5c7871987f 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java @@ -868,10 +868,9 @@ public class DefaultMQAdminExtImpl implements MQAdminExt, MQAdminExtInner { boolean force) throws RemotingException, InterruptedException, MQBrokerException { long resetOffset; if (timestamp == -1) { - - resetOffset = this.mqClientInstance.getMQClientAPIImpl().getMaxOffset(brokerAddr, queue.getTopic(), queue.getQueueId(), timeoutMillis); + resetOffset = this.mqClientInstance.getMQClientAPIImpl().getMaxOffset(brokerAddr, queue, timeoutMillis); } else { - resetOffset = this.mqClientInstance.getMQClientAPIImpl().searchOffset(brokerAddr, queue.getTopic(), queue.getQueueId(), timestamp, timeoutMillis); + resetOffset = this.mqClientInstance.getMQClientAPIImpl().searchOffset(brokerAddr, queue, timestamp, timeoutMillis); } RollbackStats rollbackStats = new RollbackStats(); @@ -889,6 +888,7 @@ public class DefaultMQAdminExtImpl implements MQAdminExt, MQAdminExtInner { requestHeader.setTopic(queue.getTopic()); requestHeader.setQueueId(queue.getQueueId()); requestHeader.setCommitOffset(resetOffset); + requestHeader.setBname(queue.getBrokerName()); this.mqClientInstance.getMQClientAPIImpl().updateConsumerOffset(brokerAddr, requestHeader, timeoutMillis); } return rollbackStats; @@ -1590,6 +1590,7 @@ public class DefaultMQAdminExtImpl implements MQAdminExt, MQAdminExtInner { requestHeader.setTopic(mq.getTopic()); requestHeader.setQueueId(mq.getQueueId()); requestHeader.setCommitOffset(offset); + requestHeader.setBname(mq.getBrokerName()); this.mqClientInstance.getMQClientAPIImpl().updateConsumerOffset(brokerAddr, requestHeader, timeoutMillis); } @@ -1634,6 +1635,7 @@ public class DefaultMQAdminExtImpl implements MQAdminExt, MQAdminExtInner { this.mqClientInstance.getMQClientAPIImpl().setMessageRequestMode(brokerAddr, topic, consumerGroup, mode, popShareQueueNum, timeoutMillis); } + @Deprecated @Override public long searchOffset(final String brokerAddr, final String topicName, final int queueId, final long timestamp, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException { diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java index 59ac6c5cb2..5f99cb69b5 100644 --- a/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java +++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java @@ -371,6 +371,7 @@ public interface MQAdminExt extends MQAdmin { throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException; + @Deprecated long searchOffset(final String brokerAddr, final String topicName, final int queueId, final long timestamp, final long timeoutMillis) throws RemotingException, MQBrokerException, InterruptedException; diff --git a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java index 17e04e7f58..e8bc91a02c 100644 --- a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java +++ b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtTest.java @@ -16,6 +16,19 @@ */ package org.apache.rocketmq.tools.admin; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import org.apache.rocketmq.client.ClientConfig; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; @@ -70,23 +83,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; - import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -467,14 +466,14 @@ public class DefaultMQAdminExtTest { @Test public void testMaxOffset() throws Exception { - when(mQClientAPIImpl.getMaxOffset(anyString(), anyString(), anyInt(), anyLong())).thenReturn(100L); + when(mQClientAPIImpl.getMaxOffset(anyString(), any(MessageQueue.class), anyLong())).thenReturn(100L); assertThat(defaultMQAdminExt.maxOffset(new MessageQueue(topic1, broker1Name, 0))).isEqualTo(100L); } @Test public void testSearchOffset() throws Exception { - when(mQClientAPIImpl.searchOffset(anyString(), anyString(), anyInt(), anyLong(), anyLong())).thenReturn(101L); + when(mQClientAPIImpl.searchOffset(anyString(), any(MessageQueue.class), anyLong(), anyLong())).thenReturn(101L); assertThat(defaultMQAdminExt.searchOffset(new MessageQueue(topic1, broker1Name, 0), System.currentTimeMillis())).isEqualTo(101L); } From d930cb96add52a1ff04871a73b618d354f691f79 Mon Sep 17 00:00:00 2001 From: lizhiboo Date: Mon, 18 Jul 2022 17:28:23 +0800 Subject: [PATCH 323/338] [ISSUE #4624] Add plain_acl_bak.xml for reset at test case start. (#4625) * add plain_acl_bak.xml to reset at test case start. * add license * reset file at test case start --- .../acl/plain/PlainAccessValidatorTest.java | 57 +++++++++++++------ acl/src/test/resources/conf/plain_acl_bak.yml | 39 +++++++++++++ 2 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 acl/src/test/resources/conf/plain_acl_bak.yml diff --git a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java index 8522e16529..51667584eb 100644 --- a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java +++ b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java @@ -470,9 +470,12 @@ public class PlainAccessValidatorTest { @Test public void addAccessAclYamlConfigTest() throws InterruptedException { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); plainAccessConfig.setAccessKey("rocketmq3"); @@ -552,8 +555,12 @@ public class PlainAccessValidatorTest { @Test public void updateAccessAclYamlConfigTest() throws InterruptedException { - String targetFileName = System.getProperty("rocketmq.home.dir") + File.separator + "conf/plain_acl.yml"; - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); + String targetFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); plainAccessConfig.setAccessKey("rocketmq3"); @@ -628,9 +635,12 @@ public class PlainAccessValidatorTest { @Test public void deleteAccessAclYamlConfigTest() throws InterruptedException { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); plainAccessConfig.setAccessKey("rocketmq3"); @@ -676,9 +686,12 @@ public class PlainAccessValidatorTest { @Test public void updateGlobalWhiteRemoteAddressesTest() throws InterruptedException { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); List globalWhiteAddrsList = new ArrayList<>(); globalWhiteAddrsList.add("192.168.1.*"); @@ -794,9 +807,12 @@ public class PlainAccessValidatorTest { @Test(expected = AclException.class) public void createAndUpdateAccessAclNullSkExceptionTest() { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/acl/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); plainAccessConfig.setAccessKey("RocketMQ33"); @@ -811,9 +827,12 @@ public class PlainAccessValidatorTest { @Test public void addAccessDefaultAclYamlConfigTest() throws InterruptedException { PlainAccessValidator plainAccessValidator = new PlainAccessValidator(); + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); plainAccessConfig.setAccessKey("watchrocketmqh"); @@ -903,9 +922,12 @@ public class PlainAccessValidatorTest { @Test public void updateAccessConfigEmptyPermListTest() { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessValidator plainAccessValidator = new PlainAccessValidator(); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); @@ -932,9 +954,12 @@ public class PlainAccessValidatorTest { @Test public void updateAccessConfigEmptyWhiteRemoteAddressTest() { + String backupFileName = System.getProperty("rocketmq.home.dir") + + File.separator + "conf/plain_acl_bak.yml".replace("/", File.separator); String targetFileName = System.getProperty("rocketmq.home.dir") - + File.separator + "conf/plain_acl.yml".replace("/", File.separator); - Map backUpAclConfigMap = AclUtils.getYamlDataObject(targetFileName, Map.class); + + File.separator + "conf/plain_acl.yml".replace("/", File.separator); + Map backUpAclConfigMap = AclUtils.getYamlDataObject(backupFileName, Map.class); + AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); PlainAccessValidator plainAccessValidator = new PlainAccessValidator(); PlainAccessConfig plainAccessConfig = new PlainAccessConfig(); diff --git a/acl/src/test/resources/conf/plain_acl_bak.yml b/acl/src/test/resources/conf/plain_acl_bak.yml new file mode 100644 index 0000000000..59bd6d4ff2 --- /dev/null +++ b/acl/src/test/resources/conf/plain_acl_bak.yml @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +## suggested format + +globalWhiteRemoteAddresses: +- 10.10.103.* +- 192.168.0.* +accounts: +- accessKey: RocketMQ + secretKey: 12345678 + whiteRemoteAddress: 192.168.0.* + admin: false + defaultTopicPerm: DENY + defaultGroupPerm: SUB + topicPerms: + - topicA=DENY + - topicB=PUB|SUB + - topicC=SUB + groupPerms: + - groupA=DENY + - groupB=SUB + - groupC=SUB +- accessKey: rocketmq2 + secretKey: 12345678 + whiteRemoteAddress: 192.168.1.* + admin: true From edf2ee00a65e0fc2b8324aa7036a53dd817a0eca Mon Sep 17 00:00:00 2001 From: "fujian.zfj" Date: Mon, 18 Jul 2022 17:36:35 +0800 Subject: [PATCH 324/338] map null exception --- store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java index 06c06e48bb..587bddb561 100644 --- a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java +++ b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java @@ -480,7 +480,7 @@ public class ConsumeQueue implements ConsumeQueueInterface, FileQueueLifeCycle { return false; } Map prop = dispatchRequest.getPropertiesMap(); - if (prop == null && prop.isEmpty()) { + if (prop == null || prop.isEmpty()) { return false; } String multiDispatchQueue = prop.get(MessageConst.PROPERTY_INNER_MULTI_DISPATCH); From ef718d2229320be294407755426b0c24656964de Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Mon, 18 Jul 2022 19:19:32 +0800 Subject: [PATCH 325/338] [ISSUE #3949] parameter validate --- .../rocketmq/proxy/config/ProxyConfig.java | 45 ++--- .../proxy/grpc/v2/common/GrpcValidator.java | 69 ++++--- .../v2/consumer/ReceiveMessageActivity.java | 8 +- .../grpc/v2/producer/SendMessageActivity.java | 64 +++--- .../grpc/v2/AbstractMessingActivityTest.java | 4 +- .../v2/producer/SendMessageActivityTest.java | 187 +++++++++++++++++- 6 files changed, 281 insertions(+), 96 deletions(-) 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 12d310a039..ca3b632821 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 @@ -56,15 +56,6 @@ public class ProxyConfig { * 130M = 4M * 32 messages + 2M attributes */ private int grpcMaxInboundMessageSize = 130 * 1024 * 1024; - - /** - * the regex to check topic name, empty string means not to check - */ - private String topicNameCheckRegex = "^[%|a-zA-Z0-9_-]{1,127}$"; - /** - * the regex to check consumer group name, empty string means not to check - */ - private String consumerGroupNameCheckRegex = "^[%a-zA-Z0-9_-]{1,64}$"; /** * max message body size, 0 or negative number means no limit for proxy */ @@ -73,13 +64,15 @@ public class ProxyConfig { * max user property size, 0 or negative number means no limit for proxy */ private int maxUserPropertySize = 16 * 1024; + private int userPropertyMaxNum = 128; /** * max message group size, 0 or negative number means no limit for proxy */ - private int maxMessageGroupSize = 1024; + private int maxMessageGroupSize = 64; private long minInvisibleTimeMillsForRecv = Duration.ofSeconds(10).toMillis(); private long maxInvisibleTimeMills = Duration.ofHours(12).toMillis(); private long maxDelayTimeMills = Duration.ofDays(1).toMillis(); + private long maxTransactionRecoverySecond = Duration.ofHours(1).getSeconds(); private boolean enableTopicMessageTypeCheck = true; private int grpcClientProducerMaxAttempts = 3; @@ -299,22 +292,6 @@ public class ProxyConfig { this.grpcMaxInboundMessageSize = grpcMaxInboundMessageSize; } - public String getTopicNameCheckRegex() { - return topicNameCheckRegex; - } - - public void setTopicNameCheckRegex(String topicNameCheckRegex) { - this.topicNameCheckRegex = topicNameCheckRegex; - } - - public String getConsumerGroupNameCheckRegex() { - return consumerGroupNameCheckRegex; - } - - public void setConsumerGroupNameCheckRegex(String consumerGroupNameCheckRegex) { - this.consumerGroupNameCheckRegex = consumerGroupNameCheckRegex; - } - public int getMaxMessageSize() { return maxMessageSize; } @@ -331,6 +308,14 @@ public class ProxyConfig { this.maxUserPropertySize = maxUserPropertySize; } + public int getUserPropertyMaxNum() { + return userPropertyMaxNum; + } + + public void setUserPropertyMaxNum(int userPropertyMaxNum) { + this.userPropertyMaxNum = userPropertyMaxNum; + } + public int getMaxMessageGroupSize() { return maxMessageGroupSize; } @@ -363,6 +348,14 @@ public class ProxyConfig { this.maxDelayTimeMills = maxDelayTimeMills; } + public long getMaxTransactionRecoverySecond() { + return maxTransactionRecoverySecond; + } + + public void setMaxTransactionRecoverySecond(long maxTransactionRecoverySecond) { + this.maxTransactionRecoverySecond = maxTransactionRecoverySecond; + } + public int getGrpcClientProducerMaxAttempts() { return grpcClientProducerMaxAttempts; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java index b4e7bc80a5..0ada96b864 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/common/GrpcValidator.java @@ -19,10 +19,10 @@ package org.apache.rocketmq.proxy.grpc.v2.common; import apache.rocketmq.v2.Code; import apache.rocketmq.v2.Resource; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; +import com.google.common.base.CharMatcher; import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.client.Validators; +import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.common.topic.TopicValidator; @@ -32,7 +32,6 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager; public class GrpcValidator { protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); - protected static final Map CHECK_PATTERN_CACHE = new ConcurrentHashMap<>(); protected static final Object INSTANCE_CREATE_LOCK = new Object(); protected static volatile GrpcValidator instance; @@ -48,17 +47,6 @@ public class GrpcValidator { return instance; } - protected Pattern getPattern(String regex) { - return CHECK_PATTERN_CACHE.compute(regex, (regexKey, oldPattern) -> { - try { - return Pattern.compile(regex); - } catch (Exception e) { - log.error("create check pattern failed. regex:{}", regex, e); - return oldPattern; - } - }); - } - public void validateTopic(Resource topic) { validateTopic(GrpcConverter.getInstance().wrapResourceWithNamespace(topic)); } @@ -70,16 +58,10 @@ public class GrpcValidator { if (TopicValidator.isSystemTopic(topicName)) { throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "cannot access system topic"); } - String regex = ConfigurationManager.getProxyConfig().getTopicNameCheckRegex(); - if (StringUtils.isBlank(regex)) { - return; - } - Pattern pattern = getPattern(regex); - if (pattern == null) { - throw new GrpcProxyException(Code.INTERNAL_SERVER_ERROR, "get topic name check pattern failed"); - } - if (!pattern.matcher(topicName).matches()) { - throw new GrpcProxyException(Code.ILLEGAL_TOPIC, "the format of topic is not correct"); + try { + Validators.checkTopic(topicName); + } catch (MQClientException mqClientException) { + throw new GrpcProxyException(Code.ILLEGAL_TOPIC, mqClientException.getErrorMessage()); } } @@ -94,16 +76,10 @@ public class GrpcValidator { if (MixAll.isSysConsumerGroup(consumerGroupName)) { throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "cannot use system consumer group"); } - String regex = ConfigurationManager.getProxyConfig().getConsumerGroupNameCheckRegex(); - if (StringUtils.isBlank(regex)) { - return; - } - Pattern pattern = getPattern(regex); - if (pattern == null) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "get consumer group check pattern failed"); - } - if (!pattern.matcher(consumerGroupName).matches()) { - throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, "the format of consumer group is not correct"); + try { + Validators.checkGroup(consumerGroupName); + } catch (MQClientException mqClientException) { + throw new GrpcProxyException(Code.ILLEGAL_CONSUMER_GROUP, mqClientException.getErrorMessage()); } } @@ -128,4 +104,27 @@ public class GrpcValidator { throw new GrpcProxyException(Code.ILLEGAL_INVISIBLE_TIME, "the invisibleTime is too large. max is " + maxInvisibleTime); } } + + public void validateTag(String tag) { + if (StringUtils.isNotEmpty(tag)) { + if (StringUtils.isBlank(tag)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot be the char sequence of whitespace"); + } + if (tag.contains("|")) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot contain '|'"); + } + if (containControlCharacter(tag)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot contain control character"); + } + } + } + + public boolean containControlCharacter(String data) { + for (int i = 0; i < data.length(); i++) { + if (CharMatcher.javaIsoControl().matches(data.charAt(i))) { + return true; + } + } + return false; + } } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java index a5d000d3d2..b69db78b11 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/consumer/ReceiveMessageActivity.java @@ -65,16 +65,20 @@ public class ReceiveMessageActivity extends AbstractMessingActivity { Settings settings = this.grpcClientSettingsManager.getClientSettings(ctx); Subscription subscription = settings.getSubscription(); boolean fifo = subscription.getFifo(); + ProxyConfig config = ConfigurationManager.getProxyConfig(); Long timeRemaining = ctx.getRemainingMs(); if (timeRemaining == null) { timeRemaining = Duration.ofSeconds(20).toMillis(); } - long pollTime = timeRemaining - ConfigurationManager.getProxyConfig().getLongPollingReserveTimeInMillis(); + long pollTime = timeRemaining - config.getLongPollingReserveTimeInMillis(); if (pollTime <= 0) { - writer.writeAndComplete(ctx, Code.MESSAGE_NOT_FOUND, "time remaining is too small"); + writer.writeAndComplete(ctx, Code.BAD_REQUEST, "time remaining is too small"); return; } + if (pollTime > config.getGrpcClientConsumerLongPollingTimeoutMillis()) { + pollTime = config.getGrpcClientConsumerLongPollingTimeoutMillis(); + } validateTopicAndConsumerGroup(request.getMessageQueue().getTopic(), request.getGroup()); String topic = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getMessageQueue().getTopic()); 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 589705ca5c..be91ccf4d4 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 @@ -43,11 +43,13 @@ import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.sysflag.MessageSysFlag; 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.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.GrpcProxyException; +import org.apache.rocketmq.proxy.grpc.v2.common.GrpcValidator; import org.apache.rocketmq.proxy.grpc.v2.common.ResponseBuilder; import org.apache.rocketmq.proxy.processor.MessagingProcessor; import org.apache.rocketmq.proxy.processor.QueueSelector; @@ -139,22 +141,14 @@ public class SendMessageActivity extends AbstractMessingActivity { } } - protected void validateTag(String tag) { - if (StringUtils.isNotEmpty(tag)) { - if (StringUtils.isBlank(tag)) { - throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot be the char sequence of whitespace"); - } - if (tag.contains("|")) { - throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_TAG, "tag cannot contain '|'"); - } - } - } - protected void validateMessageKey(String key) { if (StringUtils.isNotEmpty(key)) { if (StringUtils.isBlank(key)) { throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_KEY, "key cannot be the char sequence of whitespace"); } + if (GrpcValidator.getInstance().containControlCharacter(key)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_KEY, "key cannot contain control character"); + } } } @@ -170,20 +164,8 @@ public class SendMessageActivity extends AbstractMessingActivity { if (messageGroup.length() >= maxSize) { throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_GROUP, "message group exceed the max size " + maxSize); } - } - } - - protected void validateMessagePropertySize(Map property) { - int maxSize = ConfigurationManager.getProxyConfig().getMaxUserPropertySize(); - if (maxSize <= 0) { - return; - } - int curSize = 0; - for (Map.Entry entry : property.entrySet()) { - curSize += entry.getKey().length(); - curSize += entry.getValue().length(); - if (curSize > maxSize) { - throw new GrpcProxyException(Code.MESSAGE_PROPERTIES_TOO_LARGE, "the size of message properties cannot exceed the max " + maxSize); + if (GrpcValidator.getInstance().containControlCharacter(messageGroup)) { + throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_GROUP, "message group cannot contain control character"); } } } @@ -194,35 +176,58 @@ public class SendMessageActivity extends AbstractMessingActivity { return; } if (deliveryTimestampMs - System.currentTimeMillis() > maxDelay) { - throw new GrpcProxyException(Code.ILLEGAL_DELIVERY_TIME, "the max delay time of message is too large"); + throw new GrpcProxyException(Code.ILLEGAL_DELIVERY_TIME, "the max delay time of message is too large, max is " + maxDelay); + } + } + + protected void validateTransactionRecoverySecond(long transactionRecoverySecond) { + long maxTransactionRecoverySecond = ConfigurationManager.getProxyConfig().getMaxTransactionRecoverySecond(); + if (maxTransactionRecoverySecond <= 0) { + return; + } + if (transactionRecoverySecond > maxTransactionRecoverySecond) { + throw new GrpcProxyException(Code.BAD_REQUEST, "the max transaction recovery time of message is too large, max is " + maxTransactionRecoverySecond); } } protected Map buildMessageProperty(ProxyContext context, apache.rocketmq.v2.Message message, String producerGroup) { + long userPropertySize = 0; + ProxyConfig config = ConfigurationManager.getProxyConfig(); org.apache.rocketmq.common.message.Message messageWithHeader = new org.apache.rocketmq.common.message.Message(); // set user properties Map userProperties = message.getUserPropertiesMap(); + if (userProperties.size() > config.getUserPropertyMaxNum()) { + throw new GrpcProxyException(Code.MESSAGE_PROPERTIES_TOO_LARGE, "too many user properties, max is " + config.getUserPropertyMaxNum()); + } for (Map.Entry userPropertiesEntry : userProperties.entrySet()) { if (MessageConst.STRING_HASH_SET.contains(userPropertiesEntry.getKey())) { throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + userPropertiesEntry.getKey()); } + userPropertySize += userPropertiesEntry.getKey().length(); + userPropertySize += userPropertiesEntry.getValue().length(); } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); // set tag String tag = message.getSystemProperties().getTag(); - validateTag(tag); + GrpcValidator.getInstance().validateTag(tag); messageWithHeader.setTags(tag); + userPropertySize += tag.length(); // set keys List keysList = message.getSystemProperties().getKeysList(); for (String key : keysList) { validateMessageKey(key); + userPropertySize += key.length(); } if (keysList.size() > 0) { messageWithHeader.setKeys(keysList); } + if (userPropertySize > config.getMaxUserPropertySize()) { + throw new GrpcProxyException(Code.MESSAGE_PROPERTIES_TOO_LARGE, "the total size of user property is too large, max is " + config.getMaxUserPropertySize()); + } + // set message id String messageId = message.getSystemProperties().getMessageId(); if (StringUtils.isBlank(messageId)) { @@ -236,8 +241,10 @@ public class SendMessageActivity extends AbstractMessingActivity { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); if (message.getSystemProperties().hasOrphanedTransactionRecoveryDuration()) { + long transactionRecoverySecond = Durations.toSeconds(message.getSystemProperties().getOrphanedTransactionRecoveryDuration()); + validateTransactionRecoverySecond(transactionRecoverySecond); MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS, - String.valueOf(Durations.toSeconds(message.getSystemProperties().getOrphanedTransactionRecoveryDuration()))); + String.valueOf(transactionRecoverySecond)); } } @@ -276,7 +283,6 @@ public class SendMessageActivity extends AbstractMessingActivity { MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_BORN_HOST, bornHost); } - validateMessagePropertySize(messageWithHeader.getProperties()); return messageWithHeader.getProperties(); } diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java index ea1b67d01c..3dad901daf 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/AbstractMessingActivityTest.java @@ -63,8 +63,8 @@ public class AbstractMessingActivityTest extends InitConfigAndLoggerTest { assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().build())); assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(MixAll.CID_SYS_RMQ_TRANS).build())); assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName("@").build())); - assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(65)).build())); - messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(64)).build()); + assertThrows(GrpcProxyException.class, () -> messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(256)).build())); + messingActivity.validateConsumerGroup(Resource.newBuilder().setName(createString(255)).build()); } private static String createString(int len) { 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 130d5521dc..dc57cd3d98 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 @@ -28,7 +28,9 @@ import apache.rocketmq.v2.SystemProperties; import com.google.protobuf.ByteString; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import java.time.Duration; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.apache.commons.lang3.StringUtils; @@ -43,6 +45,7 @@ import org.apache.rocketmq.common.protocol.route.QueueData; import org.apache.rocketmq.common.protocol.route.TopicRouteData; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.proxy.common.ProxyContext; +import org.apache.rocketmq.proxy.config.ConfigurationManager; import org.apache.rocketmq.proxy.grpc.v2.BaseActivityTest; import org.apache.rocketmq.proxy.grpc.v2.common.GrpcProxyException; import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue; @@ -425,6 +428,35 @@ public class SendMessageActivityTest extends BaseActivityTest { } }); + // tag with \t + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setTag("\t") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_TAG, e.getCode()); + throw e; + } + }); + // blank message key assertThrows(GrpcProxyException.class, () -> { try { @@ -454,6 +486,35 @@ public class SendMessageActivityTest extends BaseActivityTest { } }); + // blank message with \t + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .addKeys("\t") + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_KEY, e.getCode()); + throw e; + } + }); + // blank message group assertThrows(GrpcProxyException.class, () -> { try { @@ -496,7 +557,36 @@ public class SendMessageActivityTest extends BaseActivityTest { .setSystemProperties(SystemProperties.newBuilder() .setMessageId("msgId") .setQueueId(0) - .setMessageGroup(createStr(1025)) + .setMessageGroup(createStr(ConfigurationManager.getProxyConfig().getMaxMessageGroupSize() + 1)) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_MESSAGE_GROUP, e.getCode()); + throw e; + } + }); + + // message group with \t + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageGroup("\t") .setMessageType(MessageType.NORMAL) .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) @@ -529,7 +619,40 @@ public class SendMessageActivityTest extends BaseActivityTest { .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) .build()) - .putUserProperties("key", createStr(16 * 1024)) + .putUserProperties("key", createStr(16 * 1024 + 1)) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.MESSAGE_PROPERTIES_TOO_LARGE, e.getCode()); + throw e; + } + }); + + // too large message property + assertThrows(GrpcProxyException.class, () -> { + Map p = new HashMap<>(); + for (int i = 0; i <= ConfigurationManager.getProxyConfig().getUserPropertyMaxNum(); i++) { + p.put(String.valueOf(i), String.valueOf(i)); + } + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("msgId") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .putAllUserProperties(p) .setBody(ByteString.copyFrom(new byte[3])) .build()) .build() @@ -597,6 +720,66 @@ public class SendMessageActivityTest extends BaseActivityTest { throw e; } }); + + // delay time + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("id") + .setDeliveryTimestamp( + Timestamps.fromMillis(System.currentTimeMillis() + Duration.ofDays(1).toMillis() + Duration.ofSeconds(10).toMillis())) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.ILLEGAL_DELIVERY_TIME, e.getCode()); + throw e; + } + }); + + // transactionRecoverySecond + assertThrows(GrpcProxyException.class, () -> { + try { + this.sendMessageActivity.sendMessage( + createContext(), + SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(TOPIC) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId("id") + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .setOrphanedTransactionRecoveryDuration(Durations.fromHours(2)) + .setMessageType(MessageType.TRANSACTION) + .build()) + .setBody(ByteString.copyFrom(new byte[3])) + .build()) + .build() + ).get(); + } catch (ExecutionException t) { + GrpcProxyException e = (GrpcProxyException) t.getCause(); + assertEquals(Code.BAD_REQUEST, e.getCode()); + throw e; + } + }); } private static String createStr(int len) { From 94153b0311c5a5d6c25d6ef4ad4b3f8802edbaf1 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 15:00:46 +0800 Subject: [PATCH 326/338] [ISSUE #3949] Check handleGroup --- .../rocketmq/proxy/processor/ReceiptHandleProcessor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java index 0c8b2fdd74..dc91061fdd 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ReceiptHandleProcessor.java @@ -243,6 +243,9 @@ public class ReceiptHandleProcessor extends AbstractStartAndShutdown { ProxyConfig proxyConfig = ConfigurationManager.getProxyConfig(); ProxyContext context = createContext("ClearGroup"); ReceiptHandleGroup handleGroup = receiptHandleGroupMap.remove(key); + if (handleGroup == null) { + return; + } handleGroup.scan((msgID, handle, messageReceiptHandle) -> { ReceiptHandle receiptHandle = ReceiptHandle.decode(messageReceiptHandle.getReceiptHandle()); messagingProcessor.changeInvisibleTime( From 657d5edfb9dacf341a67a013a6087ca2f104a698 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 19 Jul 2022 16:38:49 +0800 Subject: [PATCH 327/338] [ISSUE #3949] set delay level for message; use byte to calculate property size --- .../rocketmq/proxy/config/ConfigFile.java | 23 ++++++ .../rocketmq/proxy/config/Configuration.java | 1 + .../rocketmq/proxy/config/ProxyConfig.java | 78 ++++++++++++++++++- .../grpc/v2/producer/SendMessageActivity.java | 37 +++++---- .../v2/producer/SendMessageActivityTest.java | 5 +- .../rocketmq/test/grpc/v2/ClusterGrpcIT.java | 4 + .../rocketmq/test/grpc/v2/GrpcBaseIT.java | 49 ++++++++++++ .../rocketmq/test/grpc/v2/LocalGrpcIT.java | 5 ++ 8 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigFile.java diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigFile.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigFile.java new file mode 100644 index 0000000000..37757f8d63 --- /dev/null +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigFile.java @@ -0,0 +1,23 @@ +/* + * 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.config; + +public interface ConfigFile { + + void initData(); +} diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java index 89eed7fa93..cf0b715936 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java @@ -36,6 +36,7 @@ public class Configuration { } ProxyConfig proxyConfig = JSON.parseObject(proxyConfigData, ProxyConfig.class); + proxyConfig.initData(); setProxyConfig(proxyConfig); } 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 ca3b632821..bc7c58b6a0 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 @@ -18,10 +18,20 @@ package org.apache.rocketmq.proxy.config; import java.time.Duration; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.proxy.ProxyMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class ProxyConfig { +public class ProxyConfig implements ConfigFile { + private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME); public final static String CONFIG_FILE_NAME = "rmq-proxy.json"; private static final int PROCESSOR_NUMBER = Runtime.getRuntime().availableProcessors(); @@ -136,10 +146,56 @@ public class ProxyConfig { private boolean enableACL = false; + private boolean useDelayLevel = true; + private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"; + private transient Map delayLevelTable = new ConcurrentHashMap<>(); + private int metricCollectorMode = MetricCollectorMode.OFF.getOrdinal(); // Example address: 127.0.0.1:1234 private String metricCollectorAddress = ""; + @Override + public void initData() { + parseDelayLevel(); + } + + public int computeDelayLevel(long timeMillis) { + long intervalMillis = timeMillis - System.currentTimeMillis(); + List> sortedLevels = delayLevelTable.entrySet().stream().sorted(Comparator.comparingLong(Map.Entry::getValue)).collect(Collectors.toList()); + for (Map.Entry entry : sortedLevels) { + if (entry.getValue() > intervalMillis) { + return entry.getKey(); + } + } + return sortedLevels.get(sortedLevels.size() - 1).getKey(); + } + + public void parseDelayLevel() { + this.delayLevelTable = new ConcurrentHashMap<>(); + Map timeUnitTable = new HashMap<>(); + timeUnitTable.put("s", 1000L); + timeUnitTable.put("m", 1000L * 60); + timeUnitTable.put("h", 1000L * 60 * 60); + timeUnitTable.put("d", 1000L * 60 * 60 * 24); + + String levelString = this.getMessageDelayLevel(); + try { + String[] levelArray = levelString.split(" "); + for (int i = 0; i < levelArray.length; i++) { + String value = levelArray[i]; + String ch = value.substring(value.length() - 1); + Long tu = timeUnitTable.get(ch); + + int level = i + 1; + long num = Long.parseLong(value.substring(0, value.length() - 1)); + long delayTimeMillis = tu * num; + this.delayLevelTable.put(level, delayTimeMillis); + } + } catch (Exception e) { + log.error("parse delay level failed. messageDelayLevel:{}", messageDelayLevel, e); + } + } + public String getRocketMQClusterName() { return rocketMQClusterName; } @@ -779,4 +835,24 @@ public class ProxyConfig { public void setMetricCollectorAddress(String metricCollectorAddress) { this.metricCollectorAddress = metricCollectorAddress; } + + public boolean isUseDelayLevel() { + return useDelayLevel; + } + + public void setUseDelayLevel(boolean useDelayLevel) { + this.useDelayLevel = useDelayLevel; + } + + public String getMessageDelayLevel() { + return messageDelayLevel; + } + + public void setMessageDelayLevel(String messageDelayLevel) { + this.messageDelayLevel = messageDelayLevel; + } + + public Map getDelayLevelTable() { + return delayLevelTable; + } } 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 be91ccf4d4..87a8fedec8 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 @@ -29,6 +29,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -161,7 +162,7 @@ public class SendMessageActivity extends AbstractMessingActivity { if (maxSize <= 0) { return; } - if (messageGroup.length() >= maxSize) { + if (messageGroup.getBytes(StandardCharsets.UTF_8).length >= maxSize) { throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_GROUP, "message group exceed the max size " + maxSize); } if (GrpcValidator.getInstance().containControlCharacter(messageGroup)) { @@ -203,8 +204,8 @@ public class SendMessageActivity extends AbstractMessingActivity { if (MessageConst.STRING_HASH_SET.contains(userPropertiesEntry.getKey())) { throw new GrpcProxyException(Code.ILLEGAL_MESSAGE_PROPERTY_KEY, "property is used by system: " + userPropertiesEntry.getKey()); } - userPropertySize += userPropertiesEntry.getKey().length(); - userPropertySize += userPropertiesEntry.getValue().length(); + userPropertySize += userPropertiesEntry.getKey().getBytes(StandardCharsets.UTF_8).length; + userPropertySize += userPropertiesEntry.getValue().getBytes(StandardCharsets.UTF_8).length; } MessageAccessor.setProperties(messageWithHeader, Maps.newHashMap(userProperties)); @@ -212,13 +213,13 @@ public class SendMessageActivity extends AbstractMessingActivity { String tag = message.getSystemProperties().getTag(); GrpcValidator.getInstance().validateTag(tag); messageWithHeader.setTags(tag); - userPropertySize += tag.length(); + userPropertySize += tag.getBytes(StandardCharsets.UTF_8).length; // set keys List keysList = message.getSystemProperties().getKeysList(); for (String key : keysList) { validateMessageKey(key); - userPropertySize += key.length(); + userPropertySize += key.getBytes(StandardCharsets.UTF_8).length; } if (keysList.size() > 0) { messageWithHeader.setKeys(keysList); @@ -249,14 +250,7 @@ public class SendMessageActivity extends AbstractMessingActivity { } // set delay level or deliver timestamp - if (message.getSystemProperties().hasDeliveryTimestamp()) { - Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); - long deliveryTimestampMs = Timestamps.toMillis(deliveryTimestamp); - validateDelayTime(deliveryTimestampMs); - - String timestampString = String.valueOf(deliveryTimestampMs); - MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); - } + fillDelayMessageProperty(message, messageWithHeader); // set reconsume times int reconsumeTimes = message.getSystemProperties().getDeliveryAttempt(); @@ -286,6 +280,23 @@ public class SendMessageActivity extends AbstractMessingActivity { return messageWithHeader.getProperties(); } + protected void fillDelayMessageProperty(apache.rocketmq.v2.Message message, org.apache.rocketmq.common.message.Message messageWithHeader) { + if (message.getSystemProperties().hasDeliveryTimestamp()) { + Timestamp deliveryTimestamp = message.getSystemProperties().getDeliveryTimestamp(); + long deliveryTimestampMs = Timestamps.toMillis(deliveryTimestamp); + validateDelayTime(deliveryTimestampMs); + + ProxyConfig config = ConfigurationManager.getProxyConfig(); + if (config.isUseDelayLevel()) { + int delayLevel = config.computeDelayLevel(deliveryTimestampMs); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(delayLevel)); + } + + String timestampString = String.valueOf(deliveryTimestampMs); + MessageAccessor.putProperty(messageWithHeader, MessageConst.PROPERTY_TIMER_DELIVER_MS, timestampString); + } + } + protected SendMessageResponse convertToSendMessageResponse(ProxyContext ctx, SendMessageRequest request, List resultList) { SendMessageResponse.Builder builder = SendMessageResponse.newBuilder(); 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 dc57cd3d98..7776d387e5 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 @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; @@ -203,7 +204,7 @@ public class SendMessageActivityTest extends BaseActivityTest { @Test public void testBuildMessage() { - long deliveryTime = System.currentTimeMillis(); + long deliveryTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(5); String msgId = MessageClientIDSetter.createUniqID(); org.apache.rocketmq.common.message.Message messageExt = this.sendMessageActivity.buildMessage(null, @@ -226,7 +227,7 @@ public class SendMessageActivityTest extends BaseActivityTest { Resource.newBuilder().setName(TOPIC).build()).get(0); assertEquals(MessageClientIDSetter.getUniqID(messageExt), msgId); - assertEquals(String.valueOf(deliveryTime), messageExt.getProperty(MessageConst.PROPERTY_TIMER_DELIVER_MS)); + assertEquals(String.valueOf(2), messageExt.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL)); } @Test diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java index f97b7c1f9f..88f4e8ba25 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/ClusterGrpcIT.java @@ -87,6 +87,10 @@ public class ClusterGrpcIT extends GrpcBaseIT { super.testTransactionCheckThenCommit(); } + @Test + public void testSimpleConsumerSendAndRecvDelayMessage() throws Exception { + super.testSimpleConsumerSendAndRecvDelayMessage(); + } @Test public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java index 276ab9744b..35f01920dc 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/GrpcBaseIT.java @@ -84,6 +84,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import javax.net.ssl.SSLException; @@ -308,6 +309,54 @@ public class GrpcBaseIT extends BaseConf { .build(); } + public void testSimpleConsumerSendAndRecvDelayMessage() throws Exception { + String topic = initTopicOnSampleTopicBroker(broker1Name, TopicMessageType.DELAY); + String group = MQRandomUtils.getRandomConsumerGroup(); + long delayTime = TimeUnit.SECONDS.toMillis(5); + + // init consumer offset + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); + receiveMessage(blockingStub, topic, group, 1); + + this.sendClientSettings(stub, buildProducerClientSettings(topic)).get(); + String messageId = createUniqID(); + SendMessageResponse sendResponse = blockingStub.sendMessage(SendMessageRequest.newBuilder() + .addMessages(Message.newBuilder() + .setTopic(Resource.newBuilder() + .setName(topic) + .build()) + .setSystemProperties(SystemProperties.newBuilder() + .setMessageId(messageId) + .setQueueId(0) + .setMessageType(MessageType.NORMAL) + .setBodyEncoding(Encoding.GZIP) + .setBornTimestamp(Timestamps.fromMillis(System.currentTimeMillis())) + .setBornHost(StringUtils.defaultString(RemotingUtil.getLocalAddress(), "127.0.0.1:1234")) + .setDeliveryTimestamp(Timestamps.fromMillis(System.currentTimeMillis() + delayTime)) + .build()) + .setBody(ByteString.copyFromUtf8("hello")) + .build()) + .build()); + long sendTime = System.currentTimeMillis(); + assertSendMessage(sendResponse, messageId); + + this.sendClientSettings(stub, buildSimpleConsumerClientSettings(group)).get(); + + AtomicLong recvTime = new AtomicLong(); + AtomicReference recvMessage = new AtomicReference<>(); + await().atMost(java.time.Duration.ofSeconds(10)).until(() -> { + List messageList = getMessageFromReceiveMessageResponse(receiveMessage(blockingStub, topic, group)); + if (messageList.isEmpty()) { + return false; + } + recvTime.set(System.currentTimeMillis()); + recvMessage.set(messageList.get(0)); + return messageList.get(0).getSystemProperties().getMessageId().equals(messageId); + }); + + assertThat(Math.abs(recvTime.get() - sendTime - delayTime) < 2 * 1000).isTrue(); + } + public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { String topic = initTopicOnSampleTopicBroker(broker1Name); String group = MQRandomUtils.getRandomConsumerGroup(); diff --git a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java index 84e819f203..de72069014 100644 --- a/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java +++ b/test/src/test/java/org/apache/rocketmq/test/grpc/v2/LocalGrpcIT.java @@ -75,6 +75,11 @@ public class LocalGrpcIT extends GrpcBaseIT { super.testTransactionCheckThenCommit(); } + @Test + public void testSimpleConsumerSendAndRecvDelayMessage() throws Exception { + super.testSimpleConsumerSendAndRecvDelayMessage(); + } + @Test public void testSimpleConsumerSendAndRecvBigMessage() throws Exception { super.testSimpleConsumerSendAndRecvBigMessage(); From 9f9f9ed22d06fc53a70add5f9646bd2b9dcc18b8 Mon Sep 17 00:00:00 2001 From: "Jixiang.jjx" Date: Tue, 19 Jul 2022 16:38:56 +0800 Subject: [PATCH 328/338] [ISSUE #3949] ignore exception for parsing grpc client version. --- .../apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 1ada862c8c..6e4a5cc2fb 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -279,8 +279,7 @@ public class ClientActivity extends AbstractMessingActivity { try { String tmp = StringUtils.upperCase(clientVersionStr); clientVersion = MQVersion.Version.valueOf(tmp).ordinal(); - } catch (Exception e) { - log.warn("client version from client not recognized: %s", clientVersionStr); + } catch (Exception ignored) { } } return clientVersion; From f88df48bafe3412a2b8428b672bd3bc8b5ba6bfd Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 17:56:28 +0800 Subject: [PATCH 329/338] [ISSUE #3949] Set topic for LocalMessageService --- .../service/message/LocalMessageService.java | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) 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 ca57457efb..93878f286c 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 @@ -238,16 +238,14 @@ public class LocalMessageService implements MessageService { PopMessageResponseHeader responseHeader = (PopMessageResponseHeader) r.readCustomHeader(); if (popStatus == PopStatus.FOUND) { - Map startOffsetInfo = null; - Map> msgOffsetInfo = null; - Map orderCountInfo = null; - if (requestHeader != null) { - popResult.setInvisibleTime(responseHeader.getInvisibleTime()); - popResult.setPopTime(responseHeader.getPopTime()); - startOffsetInfo = ExtraInfoUtil.parseStartOffsetInfo(responseHeader.getStartOffsetInfo()); - msgOffsetInfo = ExtraInfoUtil.parseMsgOffsetInfo(responseHeader.getMsgOffsetInfo()); - orderCountInfo = ExtraInfoUtil.parseOrderCountInfo(responseHeader.getOrderCountInfo()); - } + Map startOffsetInfo; + Map> msgOffsetInfo; + Map orderCountInfo; + popResult.setInvisibleTime(responseHeader.getInvisibleTime()); + popResult.setPopTime(responseHeader.getPopTime()); + startOffsetInfo = ExtraInfoUtil.parseStartOffsetInfo(responseHeader.getStartOffsetInfo()); + msgOffsetInfo = ExtraInfoUtil.parseMsgOffsetInfo(responseHeader.getMsgOffsetInfo()); + orderCountInfo = ExtraInfoUtil.parseOrderCountInfo(responseHeader.getOrderCountInfo()); // Map> sortMap = new HashMap<>(16); for (MessageExt messageExt : messageExtList) { @@ -259,38 +257,37 @@ public class LocalMessageService implements MessageService { } Map map = new HashMap<>(5); for (MessageExt messageExt : messageExtList) { - if (requestHeader != null) { - if (startOffsetInfo == null) { - // we should set the check point info to extraInfo field , if the command is popMsg - // find pop ck offset - String key = messageExt.getTopic() + messageExt.getQueueId(); - if (!map.containsKey(messageExt.getTopic() + messageExt.getQueueId())) { - map.put(key, ExtraInfoUtil.buildExtraInfo(messageExt.getQueueOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), responseHeader.getReviveQid(), - messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId())); - } - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, map.get(key) + MessageConst.KEY_SEPARATOR + messageExt.getQueueOffset()); - } else { - String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); - int index = sortMap.get(key).indexOf(messageExt.getQueueOffset()); - Long msgQueueOffset = msgOffsetInfo.get(key).get(index); - if (msgQueueOffset != messageExt.getQueueOffset()) { - log.warn("Queue offset [{}] of msg is strange, not equal to the stored in msg, {}", msgQueueOffset, messageExt); - } + if (startOffsetInfo == null) { + // we should set the check point info to extraInfo field , if the command is popMsg + // find pop ck offset + String key = messageExt.getTopic() + messageExt.getQueueId(); + if (!map.containsKey(messageExt.getTopic() + messageExt.getQueueId())) { + map.put(key, ExtraInfoUtil.buildExtraInfo(messageExt.getQueueOffset(), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), responseHeader.getReviveQid(), + messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId())); + } + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, map.get(key) + MessageConst.KEY_SEPARATOR + messageExt.getQueueOffset()); + } else { + String key = ExtraInfoUtil.getStartOffsetInfoMapKey(messageExt.getTopic(), messageExt.getQueueId()); + int index = sortMap.get(key).indexOf(messageExt.getQueueOffset()); + Long msgQueueOffset = msgOffsetInfo.get(key).get(index); + if (msgQueueOffset != messageExt.getQueueOffset()) { + log.warn("Queue offset [{}] of msg is strange, not equal to the stored in msg, {}", msgQueueOffset, messageExt); + } - messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, - ExtraInfoUtil.buildExtraInfo(startOffsetInfo.get(key), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), - responseHeader.getReviveQid(), messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId(), msgQueueOffset) - ); - if (requestHeader.isOrder() && orderCountInfo != null) { - Integer count = orderCountInfo.get(key); - if (count != null && count > 0) { - messageExt.setReconsumeTimes(count); - } + messageExt.getProperties().put(MessageConst.PROPERTY_POP_CK, + ExtraInfoUtil.buildExtraInfo(startOffsetInfo.get(key), responseHeader.getPopTime(), responseHeader.getInvisibleTime(), + responseHeader.getReviveQid(), messageExt.getTopic(), messageQueue.getBrokerName(), messageExt.getQueueId(), msgQueueOffset) + ); + if (requestHeader.isOrder() && orderCountInfo != null) { + Integer count = orderCountInfo.get(key); + if (count != null && count > 0) { + messageExt.setReconsumeTimes(count); } } - messageExt.getProperties().computeIfAbsent(MessageConst.PROPERTY_FIRST_POP_TIME, k -> String.valueOf(responseHeader.getPopTime())); } + messageExt.getProperties().computeIfAbsent(MessageConst.PROPERTY_FIRST_POP_TIME, k -> String.valueOf(responseHeader.getPopTime())); messageExt.setBrokerName(messageExt.getBrokerName()); + messageExt.setTopic(messageQueue.getTopic()); } } return popResult; From 6bcda57b367989ecf55ed5530ccef271d1e48ca7 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 17:57:53 +0800 Subject: [PATCH 330/338] [ISSUE #3949] Remove unused variables --- .../apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 6e4a5cc2fb..61b3fd04e6 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -86,9 +86,6 @@ public class ClientActivity extends AbstractMessingActivity { CompletableFuture future = new CompletableFuture<>(); try { - String clientId = ctx.getClientID(); - LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); - Settings clientSettings = grpcClientSettingsManager.getClientSettings(ctx); if (clientSettings == null) { future.complete(HeartbeatResponse.newBuilder() From 77df4ce108a498a39c91977af219150971e10a22 Mon Sep 17 00:00:00 2001 From: "kaiyi.lk" Date: Tue, 19 Jul 2022 19:07:04 +0800 Subject: [PATCH 331/338] [ISSUE #3949] doc --- .../rocketmq/common/subscription/ExponentialRetryPolicy.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java b/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java index 04f654a6e6..6f212b591e 100644 --- a/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java +++ b/common/src/main/java/org/apache/rocketmq/common/subscription/ExponentialRetryPolicy.java @@ -20,9 +20,6 @@ package org.apache.rocketmq.common.subscription; import com.google.common.base.MoreObjects; import java.util.concurrent.TimeUnit; -/** - * next delay time = min(max, initial * multiplier^reconsumeTimes) - */ public class ExponentialRetryPolicy implements RetryPolicy { private long initial = TimeUnit.SECONDS.toMillis(5); private long max = TimeUnit.HOURS.toMillis(2); From 852e9545d3ee9b5b28bce79c87aa1dec07d00d8c Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 20:35:13 +0800 Subject: [PATCH 332/338] [ISSUE #3949] Add updateSubscription for registerConsumer --- .../rocketmq/broker/client/ConsumerManager.java | 12 +++++++++++- .../proxy/grpc/v2/client/ClientActivity.java | 9 +++++---- .../rocketmq/proxy/processor/ClientProcessor.java | 6 ++++-- .../proxy/processor/DefaultMessagingProcessor.java | 4 ++-- .../rocketmq/proxy/processor/MessagingProcessor.java | 3 ++- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java index ed277a711d..6b41714691 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java @@ -118,6 +118,13 @@ public class ConsumerManager { public boolean registerConsumer(final String group, final ClientChannelInfo clientChannelInfo, ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, final Set subList, boolean isNotifyConsumerIdsChangedEnable) { + return registerConsumer(group, clientChannelInfo, consumeType, messageModel, consumeFromWhere, subList, + isNotifyConsumerIdsChangedEnable, true); + } + + public boolean registerConsumer(final String group, final ClientChannelInfo clientChannelInfo, + ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, + final Set subList, boolean isNotifyConsumerIdsChangedEnable, boolean updateSubscription) { long start = System.currentTimeMillis(); ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group); if (null == consumerGroupInfo) { @@ -131,7 +138,10 @@ public class ConsumerManager { boolean r1 = consumerGroupInfo.updateChannel(clientChannelInfo, consumeType, messageModel, consumeFromWhere); - boolean r2 = consumerGroupInfo.updateSubscription(subList); + boolean r2 = false; + if (updateSubscription) { + r2 = consumerGroupInfo.updateSubscription(subList); + } if (r1 || r2) { if (isNotifyConsumerIdsChangedEnable) { diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java index 61b3fd04e6..1f58e70661 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivity.java @@ -105,7 +105,7 @@ public class ClientActivity extends AbstractMessingActivity { case SIMPLE_CONSUMER: { validateConsumerGroup(request.getGroup()); String consumerGroup = GrpcConverter.getInstance().wrapResourceWithNamespace(request.getGroup()); - this.registerConsumer(ctx, consumerGroup, clientSettings.getClientType(), clientSettings.getSubscription().getSubscriptionsList()); + this.registerConsumer(ctx, consumerGroup, clientSettings.getClientType(), clientSettings.getSubscription().getSubscriptionsList(), false); break; } default: { @@ -227,7 +227,7 @@ public class ClientActivity extends AbstractMessingActivity { if (settings.hasSubscription()) { validateConsumerGroup(settings.getSubscription().getGroup()); String groupName = GrpcConverter.getInstance().wrapResourceWithNamespace(settings.getSubscription().getGroup()); - GrpcClientChannel consumerChannel = registerConsumer(ctx, groupName, settings.getClientType(), settings.getSubscription().getSubscriptionsList()); + GrpcClientChannel consumerChannel = registerConsumer(ctx, groupName, settings.getClientType(), settings.getSubscription().getSubscriptionsList(), true); consumerChannel.setClientObserver(responseObserver); } @@ -251,7 +251,7 @@ public class ClientActivity extends AbstractMessingActivity { return channel; } - protected GrpcClientChannel registerConsumer(ProxyContext ctx, String consumerGroup, ClientType clientType, List subscriptionEntryList) { + protected GrpcClientChannel registerConsumer(ProxyContext ctx, String consumerGroup, ClientType clientType, List subscriptionEntryList, boolean updateSubscription) { String clientId = ctx.getClientID(); LanguageCode languageCode = LanguageCode.valueOf(ctx.getLanguage()); @@ -265,7 +265,8 @@ public class ClientActivity extends AbstractMessingActivity { this.buildConsumeType(clientType), MessageModel.CLUSTERING, ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET, - this.buildSubscriptionDataSet(subscriptionEntryList) + this.buildSubscriptionDataSet(subscriptionEntryList), + updateSubscription ); return channel; } diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java index f56627a257..9225289822 100644 --- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java +++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/ClientProcessor.java @@ -71,7 +71,8 @@ public class ClientProcessor extends AbstractProcessor { ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, - Set subList + Set subList, + boolean updateSubscription ) { this.serviceManager.getConsumerManager().registerConsumer( consumerGroup, @@ -80,7 +81,8 @@ public class ClientProcessor extends AbstractProcessor { messageModel, consumeFromWhere, subList, - false); + false, + updateSubscription); } public ClientChannelInfo findConsumerChannel( 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 23dd3c86a5..5234237a22 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 @@ -241,8 +241,8 @@ public class DefaultMessagingProcessor extends AbstractStartAndShutdown implemen @Override public void registerConsumer(ProxyContext ctx, String consumerGroup, ClientChannelInfo clientChannelInfo, ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, - Set subList) { - this.clientProcessor.registerConsumer(ctx, consumerGroup, clientChannelInfo, consumeType, messageModel, consumeFromWhere, subList); + Set subList, boolean updateSubscription) { + this.clientProcessor.registerConsumer(ctx, consumerGroup, clientChannelInfo, consumeType, messageModel, consumeFromWhere, subList, updateSubscription); } @Override 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 35015b6aee..e0ae714710 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 @@ -259,7 +259,8 @@ public interface MessagingProcessor extends StartAndShutdown { ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere, - Set subList + Set subList, + boolean updateSubscription ); ClientChannelInfo findConsumerChannel( From 094a78d011c9c34bc59de56ccce01321b72bdc6f Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 20:50:29 +0800 Subject: [PATCH 333/338] [ISSUE #3949] fix unit test --- .../rocketmq/proxy/grpc/v2/client/ClientActivityTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java index 375841b9d3..89299cf4c9 100644 --- a/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java +++ b/proxy/src/test/java/org/apache/rocketmq/proxy/grpc/v2/client/ClientActivityTest.java @@ -62,6 +62,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; @@ -177,7 +178,8 @@ public class ClientActivityTest extends BaseActivityTest { any(), any(), any(), - subscriptionDatasArgumentCaptor.capture() + subscriptionDatasArgumentCaptor.capture(), + anyBoolean() ); HeartbeatResponse response = this.sendConsumerHeartbeat(context); From 973359f2e6973d63d420b32d5a463ee53319f838 Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Tue, 19 Jul 2022 20:50:41 +0800 Subject: [PATCH 334/338] [ISSUE #3949] Update rocketmq-proto to 2.0.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 241356f7c4..abffd0a279 100644 --- a/pom.xml +++ b/pom.xml @@ -124,7 +124,7 @@ 6.0.53 1.0-beta-4 1.4.2 - 2.0.0-SNAPSHOT + 2.0.0 1.45.0 3.20.1 From cdb4bd94ff830e0e21ac33adfe65c6722316e971 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 20 Jul 2022 10:08:27 +0800 Subject: [PATCH 335/338] [ISSUE #4167] Add unit test (ConsumerManagerTest) (#4633) --- .../acl/plain/PlainAccessValidatorTest.java | 3 + .../broker/client/ConsumerManagerTest.java | 155 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java diff --git a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java index 51667584eb..4fbe2319ac 100644 --- a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java +++ b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java @@ -42,6 +42,7 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -684,6 +685,8 @@ public class PlainAccessValidatorTest { AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); } + // Ignore the unstable test in the arm environment of CI + @Ignore @Test public void updateGlobalWhiteRemoteAddressesTest() throws InterruptedException { String backupFileName = System.getProperty("rocketmq.home.dir") diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java new file mode 100644 index 0000000000..b3d105a1a8 --- /dev/null +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java @@ -0,0 +1,155 @@ +/* + * 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.client; + +import io.netty.channel.Channel; +import java.util.HashSet; +import java.util.Set; +import org.apache.rocketmq.broker.BrokerController; +import org.apache.rocketmq.broker.client.net.Broker2Client; +import org.apache.rocketmq.broker.filter.ConsumerFilterManager; +import org.apache.rocketmq.common.BrokerConfig; +import org.apache.rocketmq.common.consumer.ConsumeFromWhere; +import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType; +import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; +import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData; +import org.apache.rocketmq.remoting.protocol.LanguageCode; +import org.apache.rocketmq.store.stats.BrokerStatsManager; +import org.assertj.core.api.Assertions; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerManagerTest { + + private ClientChannelInfo clientChannelInfo; + + @Mock + private Channel channel; + + private ConsumerManager consumerManager; + + private DefaultConsumerIdsChangeListener defaultConsumerIdsChangeListener; + + @Mock + private BrokerController brokerController; + + @Mock + private ConsumerFilterManager consumerFilterManager; + + private BrokerConfig brokerConfig = new BrokerConfig(); + + private Broker2Client broker2Client; + + private BrokerStatsManager brokerStatsManager; + + + private static final String GROUP = "DEFAULT_GROUP"; + + private static final String CLIENT_ID = "1"; + + private static final int VERSION = 1; + + private static final String TOPIC = "DEFAULT_TOPIC"; + + @Before + public void before() { + clientChannelInfo = new ClientChannelInfo(channel, CLIENT_ID, LanguageCode.JAVA, VERSION); + defaultConsumerIdsChangeListener = new DefaultConsumerIdsChangeListener(brokerController); + brokerStatsManager = new BrokerStatsManager(brokerConfig); + consumerManager = new ConsumerManager(defaultConsumerIdsChangeListener, brokerStatsManager); + broker2Client = new Broker2Client(brokerController); + when(brokerController.getConsumerFilterManager()).thenReturn(consumerFilterManager); + when(brokerController.getBrokerConfig()).thenReturn(brokerConfig); + when(brokerController.getBroker2Client()).thenReturn(broker2Client); + register(); + } + + @Test + public void registerConsumerTest() { + final Set subList = new HashSet<>(); + SubscriptionData subscriptionData = new SubscriptionData(TOPIC, "*"); + subList.add(subscriptionData); + consumerManager.registerConsumer(GROUP, clientChannelInfo, ConsumeType.CONSUME_PASSIVELY, + MessageModel.BROADCASTING, ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET, subList, true); + Assertions.assertThat(consumerManager.getConsumerTable().get(GROUP)).isNotNull(); + } + + @Test + public void unregisterConsumerTest() { + // register + register(); + + // unregister + consumerManager.unregisterConsumer(GROUP, clientChannelInfo, true); + Assertions.assertThat(consumerManager.getConsumerTable().get(GROUP)).isNull(); + } + + @Test + public void findChannelTest() { + + final ClientChannelInfo consumerManagerChannel = consumerManager.findChannel(GROUP, CLIENT_ID); + Assertions.assertThat(consumerManagerChannel).isNotNull(); + } + + @Test + public void findSubscriptionDataTest() { + final SubscriptionData subscriptionData = consumerManager.findSubscriptionData(GROUP, TOPIC); + Assertions.assertThat(subscriptionData).isNotNull(); + } + + @Test + public void findSubscriptionDataCountTest() { + final int count = consumerManager.findSubscriptionDataCount(GROUP); + assert count > 0; + } + + @Test + public void scanNotActiveChannelTest() { + clientChannelInfo.setLastUpdateTimestamp(System.currentTimeMillis() - 1000 * 200); + consumerManager.scanNotActiveChannel(); + assert consumerManager.getConsumerTable().size() == 0; + } + + @Test + public void queryTopicConsumeByWhoTest() { + final HashSet consumeGroup = consumerManager.queryTopicConsumeByWho(TOPIC); + assert consumeGroup.size() > 0; + } + + @Test + public void doChannelCloseEventTest() { + consumerManager.doChannelCloseEvent("127.0.0.1", channel); + assert consumerManager.getConsumerTable().size() == 0; + } + + private void register() { + // register + final Set subList = new HashSet<>(); + SubscriptionData subscriptionData = new SubscriptionData(TOPIC, "*"); + subList.add(subscriptionData); + consumerManager.registerConsumer(GROUP, clientChannelInfo, ConsumeType.CONSUME_PASSIVELY, + MessageModel.BROADCASTING, ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET, subList, true); + } + +} From 91d36fd5400c69708964de89b15dae9318d68752 Mon Sep 17 00:00:00 2001 From: RongtongJin Date: Wed, 20 Jul 2022 10:18:30 +0800 Subject: [PATCH 336/338] Remove unnecessary ignore test --- .../apache/rocketmq/acl/plain/PlainAccessValidatorTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java index 4fbe2319ac..9ea05ac760 100644 --- a/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java +++ b/acl/src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest.java @@ -42,7 +42,6 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException; import org.apache.rocketmq.remoting.protocol.RemotingCommand; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -684,9 +683,7 @@ public class PlainAccessValidatorTest { AclUtils.writeDataObject(targetFileName, backUpAclConfigMap); } - - // Ignore the unstable test in the arm environment of CI - @Ignore + @Test public void updateGlobalWhiteRemoteAddressesTest() throws InterruptedException { String backupFileName = System.getProperty("rocketmq.home.dir") From 89cb8cce876fe129553a3e4c2f56e309110d95d2 Mon Sep 17 00:00:00 2001 From: djlnet Date: Wed, 20 Jul 2022 10:20:57 +0800 Subject: [PATCH 337/338] [ISSUE #4630] Fix RequestTask's stopRun field concurrency issues(#4631) (#4631) Co-authored-by: djl --- .../java/org/apache/rocketmq/remoting/netty/RequestTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/RequestTask.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/RequestTask.java index 737ed7426d..57ed360609 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/RequestTask.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/RequestTask.java @@ -25,7 +25,7 @@ public class RequestTask implements Runnable { private final long createTimestamp = System.currentTimeMillis(); private final Channel channel; private final RemotingCommand request; - private boolean stopRun = false; + private volatile boolean stopRun = false; public RequestTask(final Runnable runnable, final Channel channel, final RemotingCommand request) { this.runnable = runnable; From a483f2c145c9464d36b279bd0528ced3afe43fdd Mon Sep 17 00:00:00 2001 From: zhouxiang Date: Wed, 20 Jul 2022 10:34:46 +0800 Subject: [PATCH 338/338] Fix unit test conflict --- ...ConsumerManagerTest.java => ConsumerManagerScannerTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename broker/src/test/java/org/apache/rocketmq/broker/client/{ConsumerManagerTest.java => ConsumerManagerScannerTest.java} (99%) diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerScannerTest.java similarity index 99% rename from broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java rename to broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerScannerTest.java index 8149cd624c..45a39996ad 100644 --- a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java +++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerScannerTest.java @@ -38,7 +38,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class ConsumerManagerTest { +public class ConsumerManagerScannerTest { private ConsumerManager consumerManager; private String group = "FooBar"; private String clientId = "clientId";